diff --git a/README.md b/README.md index a3baf35..80d486c 100644 --- a/README.md +++ b/README.md @@ -268,6 +268,24 @@ RPC source files now live under `docs/rpc//` and publish at `/rpc/0 and ($liquid|length)>0 then "mixed" + elif ($direct|length)>0 then "direct_only" + elif ($liquid|length)>0 then "liquid_only" + else "no_visible_staking_position" end + ), + direct_pools: ($direct | map(.pool_id)), + liquid_tokens: ($liquid | map({contract_id, balance})) + }' +``` + +The classifier only knows what you teach it — extend `LIQUID_PROVIDERS_JSON` as new liquid-staking products ship, and treat the result as observational rather than exhaustive. + +## Common mistakes + +- Leading with the broad account snapshot when the user only asked about one asset family. +- Using FastNear API when the user explicitly needs exact RPC fields or permissions. +- Staying in account-summary pages after the question turns into transaction history. + +## Related guides + +- [FastNear API](/api) +- [API Reference](/api/reference) +- [RPC Reference](/rpc) +- [Transactions API](/tx) +- [Choosing the Right Surface](/agents/choosing-surfaces) +- [Agent Playbooks](/agents/playbooks) diff --git a/docs/api/index.md b/docs/api/index.md index febc986..a58a4b0 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -56,6 +56,10 @@ https://test.api.fastnear.com - [V1 public key](/api/v1/public-key) when you need account resolution from a key. - [V1 FT top holders](/api/v1/ft-top) for token-distribution views. +## Need a workflow? + +Use [FastNear API Examples](/api/examples) for worked examples like account summaries, key-to-account resolution, and asset-specific follow-up. + ## Troubleshooting ### I only need one low-level value from chain state diff --git a/docs/auth/index.mdx b/docs/auth/index.mdx index a198b3b..fe5a6f7 100644 --- a/docs/auth/index.mdx +++ b/docs/auth/index.mdx @@ -25,34 +25,36 @@ import IconExternalLink from '@theme/Icon/ExternalLink'; # Auth & Access -One FastNear API key works across the RPC and API endpoints. Many public reads still work without one, but the auth model stays simple when you do need a key: use the same credential everywhere and send it either as a Bearer header or an `apiKey` query parameter. +One FastNear API key works across the RPC and API endpoints. Keep the auth model simple: use the same credential everywhere and send it either as a Bearer header or an `apiKey` query parameter. -Get a key at dashboard.fastnear.com. +Get a key in FastNear Dashboard. Live example pages also support `Copy example URL` for sharing prefilled requests. Shared example URLs run automatically on load whenever they include operation state, and saved API keys and tokens are never included in those public docs URLs. ## If you only need the rule - One FastNear API key works across RPC and API endpoints. -- Many public reads still work without a key. -- Prefer `Authorization: Bearer ${API_KEY}` for production backends. -- Use `?apiKey=${API_KEY}` when headers are awkward or you are doing quick curl/debug work. +- Set `FASTNEAR_API_KEY` in your shell, runtime, or secret manager. +- Prefer `Authorization: Bearer ${FASTNEAR_API_KEY}` for production backends. +- Use `?apiKey=${FASTNEAR_API_KEY}` when headers are awkward or you are doing quick curl/debug work. - Agents and automations should keep the key in env vars or a secret manager, not in browser storage. ## Choose the auth form | Form | Best for | Notes | | --- | --- | --- | -| `Authorization: Bearer ${API_KEY}` | production backends, workers, automations, and proxies | Best default. Keeps credentials out of copied URLs and most URL logs. | -| `?apiKey=${API_KEY}` | simple curl, one-off debugging, systems that cannot set headers easily | Valid, but the key may end up in shell history, logs, analytics, or copied links. | +| `Authorization: Bearer ${FASTNEAR_API_KEY}` | production backends, workers, automations, and proxies | Best default. Keeps credentials out of copied URLs and most URL logs. | +| `?apiKey=${FASTNEAR_API_KEY}` | simple curl, one-off debugging, systems that cannot set headers easily | Valid, but the key may end up in shell history, logs, analytics, or copied links. | If you control the client, use the header form. ## Authorization header example ```bash +: "${FASTNEAR_API_KEY:?Set FASTNEAR_API_KEY in your shell before running this example.}" + curl "https://rpc.mainnet.fastnear.com" \ - -H "Authorization: Bearer ${API_KEY}" \ + -H "Authorization: Bearer $FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` @@ -60,7 +62,9 @@ curl "https://rpc.mainnet.fastnear.com" \ ## `?apiKey=` query parameter example ```bash -curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" \ +: "${FASTNEAR_API_KEY:?Set FASTNEAR_API_KEY in your shell before running this example.}" + +curl "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` @@ -68,8 +72,8 @@ curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" \ ## Where this applies - [RPC Reference](/rpc) uses the shared FastNear key model on both the regular and archival hosts. -- API families reuse the same key shape even when public reads often work without a key. -- The docs UI can forward an optional FastNear key for supported pages, but that browser storage behavior is a docs convenience, not a production pattern. +- API families reuse the same key shape across the REST surfaces. +- The docs UI can forward a saved FastNear key for supported pages, but that browser storage behavior is a docs convenience, not a production pattern. For agent and automation runtimes, use [Auth for Agents](/agents/auth). diff --git a/docs/fastdata/kv/examples.md b/docs/fastdata/kv/examples.md new file mode 100644 index 0000000..239d909 --- /dev/null +++ b/docs/fastdata/kv/examples.md @@ -0,0 +1,108 @@ +--- +sidebar_label: Examples +slug: /fastdata/kv/examples +title: KV FastData Examples +description: Task-first KV FastData examples for exact-key checks, scoped writes, key history, and exact state follow-up. +displayed_sidebar: kvFastDataSidebar +page_actions: + - markdown +--- + +## Examples + +All shell examples below work on the public KV FastData hosts as-is. If `FASTNEAR_API_KEY` is set in your shell, they add it as a bearer header automatically; if it is unset, they fall back to the public unauthenticated path. + +### Check one exact key, then replay its history + +When you already know the contract, predecessor, and exact key, start narrow. `latest` answers the present-tense question; `history` shows whether that one row changed over time. + +```bash +CURRENT_ACCOUNT_ID=social.near +PREDECESSOR_ID=james.near +KEY='graph/follow/sleet.near' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +ENCODED_KEY="$(jq -rn --arg key "$KEY" '$key | @uri')" + +LATEST="$(curl -s "https://kv.main.fastnear.com/v0/latest/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}")" + +echo "$LATEST" | jq '{ + latest: ( + .entries[0] + | { + current_account_id, + predecessor_id, + block_height, + key, + value + } + ) +}' + +curl -s "https://kv.main.fastnear.com/v0/history/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{writes: [.entries[] | {block_height, value}]}' +``` + +For an exact follow-edge style key like this, `latest` tells you the current indexed value in one row and `history` shows whether the edge was written once or toggled over time. Start here when you already know the storage path; widen to predecessor scans only when you need discovery rather than proof. + +### Inspect one predecessor's indexed writes, then narrow to the key that changed + +`all-by-predecessor` returns the latest indexed writes one account made across every contract it touched. Lift an interesting key and replay it through `history` to see how that row changed over time. + +```bash +PREDECESSOR_ID=jemartel.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +FIRST="$(curl -s "https://kv.main.fastnear.com/v0/all/$PREDECESSOR_ID" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{"include_metadata":true,"limit":10}')" + +echo "$FIRST" | jq '{ + page_token, + entries: [.entries[] | {current_account_id, predecessor_id, block_height, key, value, tx_hash}] +}' +``` + +For `jemartel.near`, the listing mixes an `account_id` identity assertion on `contextual.near` with a run of `graph/follow/*` additions to the same contract. The `tx_hash` on each row is the direct handoff into [/tx/examples](/tx/examples#i-have-one-transaction-hash-what-happened) if you want the full transaction story behind any write. + +Lift the most recent row and replay it through `history`: + +```bash +PREDECESSOR_ID=jemartel.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +FIRST="$(curl -s "https://kv.main.fastnear.com/v0/all/$PREDECESSOR_ID" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{"include_metadata":true,"limit":10}')" + +CURRENT_ACCOUNT_ID="$(echo "$FIRST" | jq -r '.entries[0].current_account_id')" +EXACT_KEY="$(echo "$FIRST" | jq -r '.entries[0].key')" +ENCODED_KEY="$(jq -rn --arg key "$EXACT_KEY" '$key | @uri')" + +curl -s "https://kv.main.fastnear.com/v0/history/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{entries: [.entries[] | {block_height, value}]}' +``` + +For the `account_id` row, `history` returns a single write at block `185965311` with value `"jemartel.near:mainnet"` — the identity assertion stands, stable since that block. KV preserves every write equally: a quiet key shows one row, a busy key shows many — same shape, no summarization. + +## Common mistakes + +- Starting with broad account or predecessor scans when an exact key is already known. +- Using KV FastData when the user really wants balances or holdings. +- Confusing indexed history with exact current chain state. +- Reusing pagination tokens or changing filters mid-scan. + +## Related guides + +- [KV FastData API](/fastdata/kv) +- [RPC Reference](/rpc) +- [FastNear API](/api) +- [Choosing the Right Surface](/agents/choosing-surfaces) +- [Agent Playbooks](/agents/playbooks) diff --git a/docs/fastdata/kv/index.md b/docs/fastdata/kv/index.md index 9d74a9d..fb75b8d 100644 --- a/docs/fastdata/kv/index.md +++ b/docs/fastdata/kv/index.md @@ -22,6 +22,37 @@ https://kv.main.fastnear.com https://kv.test.fastnear.com ``` +## Quick start + +If you already know one exact key, start with the latest indexed row and stop as soon as it answers the question. + +```bash +CURRENT_ACCOUNT_ID=social.near +PREDECESSOR_ID=james.near +KEY='graph/follow/sleet.near' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +ENCODED_KEY="$(jq -rn --arg key "$KEY" '$key | @uri')" + +curl -s "https://kv.main.fastnear.com/v0/latest/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + latest: ( + .entries[0] + | { + current_account_id, + predecessor_id, + block_height, + key, + value + } + ) + }' +``` + +This is the narrowest useful KV read: one exact key, one latest indexed row. If the next question becomes “how did this key change over time?”, move to [GET History by Exact Key](/fastdata/kv/get-history-key) or the fuller [KV FastData Examples](/fastdata/kv/examples). + ## Use this API when - you want latest indexed state for one key or a known key family @@ -51,6 +82,10 @@ Use [FastNear API](/api) for higher-level account views, [NEAR Data API](/nearda - [All by Predecessor](/fastdata/kv/all-by-predecessor) or [History by Predecessor](/fastdata/kv/history-by-predecessor) when the predecessor is the right scope - [Multi Lookup](/fastdata/kv/multi) when you already know several exact keys +## Need a workflow? + +Use [KV FastData Examples](/fastdata/kv/examples) for worked examples like exact-key lookups, key-history investigation, predecessor-scoped inspection, and canonical RPC follow-up. + ## Default workflow 1. Pick the narrowest scope that matches the user's question. diff --git a/docs/index.md b/docs/index.md index 329b63d..c3fb25b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -165,7 +165,7 @@ import Link from '@site/src/components/LocalizedLink';
Keys and billing - Dashboard + FastNear Dashboard

Sign in, create keys, and move to higher-limit usage patterns when you need them.

diff --git a/docs/neardata/block-chunk.mdx b/docs/neardata/block-chunk.mdx index 5aea143..7177de2 100644 --- a/docs/neardata/block-chunk.mdx +++ b/docs/neardata/block-chunk.mdx @@ -1,6 +1,6 @@ --- title: Block Chunk -description: Fetch one chunk from a finalized block. +description: Fetch the lightweight per-shard chunk view for a finalized block. slug: /neardata/block-chunk hide_table_of_contents: true --- @@ -9,5 +9,8 @@ import FastnearDirectOperation from '@site/src/components/FastnearDirectOperatio # Block Chunk +This is the lightweight per-shard view of a finalized block: the chunk header, the transactions included for that shard, and the incoming receipts it executed. + +Use this when you want shard-local execution without the fuller shard envelope. It is a good fit for chunk-aware tracing, indexing, or analytics that only need the chunk payload. If you also need state changes and the receipts produced by that shard's execution, use [Block Shard](/neardata/block-shard). For a worked receipt-to-chunk tracing flow, see [RPC Examples](/rpc/examples). diff --git a/docs/neardata/block-shard.mdx b/docs/neardata/block-shard.mdx index 282c34a..8eb476a 100644 --- a/docs/neardata/block-shard.mdx +++ b/docs/neardata/block-shard.mdx @@ -1,6 +1,6 @@ --- title: Block Shard -description: Fetch one shard from a finalized block. +description: Fetch the fuller per-shard envelope for a finalized block. slug: /neardata/block-shard hide_table_of_contents: true --- @@ -9,5 +9,8 @@ import FastnearDirectOperation from '@site/src/components/FastnearDirectOperatio # Block Shard +Use this when chunk data alone is not enough and you need the fuller shard envelope for a finalized block. + +`Block Shard` goes one step wider than [Block Chunk](/neardata/block-chunk): you still get the shard's chunk payload, but you also see shard state changes and the receipts that execution produced. That makes it the better surface for debugging, indexers, and analytics when execution outcomes matter, not just included transactions and incoming receipts. For a worked tracing flow that starts from a transaction and ends on a destination chunk, see [RPC Examples](/rpc/examples). diff --git a/docs/neardata/examples.md b/docs/neardata/examples.md new file mode 100644 index 0000000..4dd9a88 --- /dev/null +++ b/docs/neardata/examples.md @@ -0,0 +1,148 @@ +--- +sidebar_label: Examples +slug: /neardata/examples +title: NEAR Data Examples +description: Task-first NEAR Data examples for live monitoring, optimistic checks, and shard-local proof. +displayed_sidebar: nearDataApiSidebar +page_actions: + - markdown +--- + +## Examples + +NEAR Data returns each block fully hydrated as one JSON document — header plus per-shard chunks, receipts, execution outcomes, and state changes — so a single `curl` gives you everything you need to filter for a specific contract without a second call. + +All shell examples below work on the public NEAR Data hosts as-is. If `FASTNEAR_API_KEY` is set in your shell, they add it as a bearer header automatically; if it is unset, they fall back to the public unauthenticated path. + +### What block is NEAR on right now? + +`/v0/last_block/final` 302-redirects to the current finalized block. Before filtering for a specific contract, it's worth seeing what one block looks like at the protocol level: transactions arrive sharded, so the tx count for a block is a sum across shards — not a single top-level number. + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + height: .block.header.height, + timestamp_nanosec: .block.header.timestamp_nanosec, + txs_per_shard: [.shards[] | {shard_id, tx_count: (.chunk.transactions | length)}], + total_txs: ([.shards[].chunk.transactions[]?] | length) + }' +``` + +A live block shows 9 shards and a handful of transactions scattered across them — most shards are empty in any given block, and activity tends to cluster on whichever shards host the busy contracts. `timestamp_nanosec` is a Unix time in nanoseconds (divide by 1e9 for seconds). With this one call you already have everything needed to dig deeper — the filtering examples below are just jq over this same response. + +### Did my contract get touched in the latest finalized block? + +`/v0/last_block/final` 302-redirects to the current finalized block. Contracts can show up in a chunk's `transactions` (when they are the `receiver_id`) or in its `receipts` (when a cross-shard call lands), so one jq pass over the shards covers both. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" \ + | jq --arg contract "$TARGET_CONTRACT" '{ + height: .block.header.height, + contract: $contract, + touched_shards: [ + .shards[] | { + shard_id, + txs: [.chunk.transactions[]? | select(.transaction.receiver_id == $contract) | .transaction.hash], + receipts: [.chunk.receipts[]? | select(.receiver_id == $contract) | .receipt_id] + } | select((.txs | length) + (.receipts | length) > 0) + ] + }' +``` + +`touched_shards: []` is a complete answer for a quiet block. A non-empty list names the shards where the contract showed up and gives you the concrete `tx` hashes or `receipt_id`s — pipe a hash into the [Transactions API](/tx) when you want the human-readable story. Receipts without matching `txs` are normal: a cross-contract call shows up as an incoming receipt in this block even if the originating transaction landed earlier. + +### Did activity show up optimistically, and did finality catch up? + +Optimistic blocks ship at `/v0/block_opt/{height}` about a second ahead of `/v0/block/{height}`. A monitoring loop can act on the optimistic signal and expect the same answer to arrive at the finalized endpoint one block later — unless network stress widens the gap, in which case the finalized fetch returns `null` and you wait. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +count_touches() { + jq --arg contract "$1" ' + [.shards[] + | ([.chunk.transactions[]? | select(.transaction.receiver_id == $contract)] | length) + + ([.chunk.receipts[]? | select(.receiver_id == $contract)] | length)] + | add // 0' +} + +OPT_LOCATION="$( + curl -s -D - -o /dev/null "${AUTH_HEADER[@]}" "https://mainnet.neardata.xyz/v0/last_block/optimistic" \ + | awk 'tolower($1) == "location:" {print $2}' | tr -d '\r' +)" +OPT_HEIGHT="${OPT_LOCATION##*/}" + +echo "optimistic @ $OPT_HEIGHT: $(curl -s "https://mainnet.neardata.xyz$OPT_LOCATION" \ + "${AUTH_HEADER[@]}" | count_touches "$TARGET_CONTRACT") touches" +FINAL="$(curl -s "https://mainnet.neardata.xyz/v0/block/$OPT_HEIGHT" \ + "${AUTH_HEADER[@]}")" +if [ "$(printf '%s' "$FINAL" | jq 'type')" = '"null"' ]; then + echo "finalized @ $OPT_HEIGHT: not caught up yet" +else + echo "finalized @ $OPT_HEIGHT: $(printf '%s' "$FINAL" | count_touches "$TARGET_CONTRACT") touches" +fi +``` + +On a healthy mainnet the two counts match within a second. The value is in the *pattern* — the optimistic stream gives you an answer you can act on immediately, with the finalized stream arriving a block later as durable confirmation. + +### Which shard actually changed my contract's state? + +Most finalized blocks show no state mutation for any given contract — activity is sparse and shard-local. Walk back from the finalized head until the contract's state actually changes, then open that shard for the mutation payload. The block-level call tells you *which* shard; the shard-level call tells you *how*. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +HEAD="$(curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" | jq '.block.header.height')" +FOUND_HEIGHT="" +FOUND_SHARD="" + +for OFFSET in $(seq 0 15); do + H=$((HEAD - OFFSET)) + SHARD="$(curl -s "https://mainnet.neardata.xyz/v0/block/$H" \ + "${AUTH_HEADER[@]}" \ + | jq -r --arg contract "$TARGET_CONTRACT" ' + .shards[] + | select([.state_changes[]? | select(.change.account_id? == $contract)] | length > 0) + | .shard_id + ' | head -1)" + if [ -n "$SHARD" ]; then + FOUND_HEIGHT=$H; FOUND_SHARD=$SHARD + break + fi +done + +if [ -z "$FOUND_HEIGHT" ]; then + echo "no state mutation for $TARGET_CONTRACT in the last 16 finalized blocks" +else + curl -s "https://mainnet.neardata.xyz/v0/block/$FOUND_HEIGHT/shard/$FOUND_SHARD" \ + "${AUTH_HEADER[@]}" \ + | jq --arg contract "$TARGET_CONTRACT" --argjson height "$FOUND_HEIGHT" --argjson shard_id "$FOUND_SHARD" '{ + height: $height, + shard_id: $shard_id, + state_changes: [.state_changes[] | select(.change.account_id? == $contract) | {type, cause: (.cause | keys[0])}][0:3], + execution_outcomes: [.receipt_execution_outcomes[] | select(.execution_outcome.outcome.executor_id == $contract) | {receipt_id: .execution_outcome.id, status: (.execution_outcome.outcome.status | keys[0])}][0:3] + }' +fi +``` + +On mainnet, `intents.near` lives on shard 7, so the walk typically lands within a handful of blocks. The shard payload names the actual state-change types (`account_update`, `data_update`, etc.) and the receipt outcomes that caused them — shard-local proof without guessing. Widen the offset range for contracts with lighter traffic. + +## When to widen + +- Use the [Transactions API](/tx) once you have a `tx_hash` and want the human-readable transaction story. +- Use the [RPC Reference](/rpc) when the next question is about exact protocol-native receipt or block semantics. +- Use [Block Headers](/neardata/block-headers) when you only need head progression or finality lag, not contract-touch inspection. diff --git a/docs/neardata/index.md b/docs/neardata/index.md index 26c6495..5e5c1bc 100644 --- a/docs/neardata/index.md +++ b/docs/neardata/index.md @@ -1,6 +1,6 @@ --- title: NEAR Data API -description: Cached and archived block-family reads for optimistic, finalized, and redirect-style block access patterns. +description: Recent block and shard reads for contract-touch monitoring, optimistic confirmation, and shard-local inspection. sidebar_position: 1 displayed_sidebar: nearDataApiSidebar slug: /neardata @@ -10,7 +10,7 @@ page_actions: # NEAR Data API -NEAR Data API is the near-realtime and block-family surface. Use it when you want fresh block slices, redirect helpers, or recent finalized and optimistic block reads without presenting it as a streaming product. +NEAR Data API is the recent block and shard surface. Use it when you want fresh block slices, contract-touch monitoring, helper redirects, or optimistic-versus-finalized confirmation without turning the product into a streaming API. ## Base URLs @@ -25,8 +25,9 @@ https://testnet.neardata.xyz ## Best fit - Polling for recent finalized or optimistic blocks. -- Block-family helpers and redirect flows. -- Lightweight freshness checks and monitoring paths. +- Detecting whether a live contract showed up or changed state in a recent block. +- Comparing optimistic signals with finalized confirmation. +- Inspecting one recent shard after you already know which block matters. ## When not to use it @@ -41,9 +42,14 @@ https://testnet.neardata.xyz ## Common starting points -- [Optimistic block](/neardata/block-optimistic) for freshest block polling. -- [Final block by height](/neardata/block) and [Block headers](/neardata/block-headers) for finalized block-family queries. -- [Last final block redirect](/neardata/last-block-final) and [Last optimistic block redirect](/neardata/last-block-optimistic) when you want helper redirects. +- [Last final block redirect](/neardata/last-block-final) and [Last optimistic block redirect](/neardata/last-block-optimistic) when you want the newest recent block quickly. +- [Final block by height](/neardata/block) for one recent hydrated block document with shard payloads attached. +- [Block Shard](/neardata/block-shard) when a recent block already identified the shard you need to inspect more closely. +- [Block Headers](/neardata/block-headers) when head progression matters more than the wider block payload. + +## Need a workflow? + +Use [NEAR Data API Examples](/neardata/examples) for worked examples like contract-touch detection, optimistic-versus-finalized comparison, and shard-local change inspection. ## Troubleshooting diff --git a/docs/rpc/examples.md b/docs/rpc/examples.md new file mode 100644 index 0000000..3bd401f --- /dev/null +++ b/docs/rpc/examples.md @@ -0,0 +1,304 @@ +--- +sidebar_label: Examples +slug: /rpc/examples +title: RPC Examples +description: Task-first RPC examples for state checks, block inspection, contract reads, and transaction submission. +displayed_sidebar: rpcSidebar +page_actions: + - markdown +--- + +# RPC Examples + +Start with the RPC method that answers the question. Use `tx` to track inclusion and finality from a tx hash, and widen only when you need receipt trees, raw state, or shard-level tracing. + +All shell examples below work on the public RPC hosts as-is. If `FASTNEAR_API_KEY` is set in your shell, they add it as a bearer header automatically; if it is unset, they fall back to the public unauthenticated path. + +## Account State + +### Show an account's balance and storage at finality + +`view_account` is the canonical RPC query for an account's current state. One call returns the unstaked balance, any stake-locked amount, storage consumed, and the block the reading was taken at. `finality: "final"` ensures you're reading stable state, not an optimistic view. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.mainnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_account",account_id:$account_id,finality:"final"} + }')" \ + | jq '.result | {amount, locked, storage_usage, block_height, block_hash}' +``` + +For `root.near`, this returns `amount` (yoctoNEAR held unstaked), `locked: "0"` (nothing in validator stake or a lockup contract), and `storage_usage: 28677` — about 28.7 KB of on-chain state. The `block_height`/`block_hash` pair anchors the reading; to read multiple accounts at the *same* block, reuse the returned `block_hash` as `block_id` on follow-up queries. + +## Transaction Inclusion and Finality + +### Track a transaction from hash to finality + +Have a tx hash? Poll `tx` with the smallest `wait_until` threshold that answers your question. + +```bash +TX_HASH=CVyG2xLJ6fuKCtULAxMnWTh2GL5ey2UUiTcgYT3M6Pow +SIGNER_ACCOUNT_ID=mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://archival-rpc.testnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" --arg signer_id "$SIGNER_ACCOUNT_ID" '{ + jsonrpc: "2.0", id: "fastnear", method: "tx", + params: {tx_hash: $tx_hash, sender_account_id: $signer_id, wait_until: "INCLUDED"} + }')" \ + | jq '{ + asked: "INCLUDED", + final_execution_status: .result.final_execution_status, + status_class: (.result.status | keys[0]), + receipts_outcome_count: (.result.receipts_outcome | length) + }' +``` + +For the pinned historical tx (a 1-yocto self-transfer from `mike.testnet`), the response comes back `FINAL` even though we asked for `INCLUDED`. That's the rule: **`wait_until` is a minimum threshold, not a target.** The node returns whatever stage the tx actually reached — for a historical tx that's always `FINAL`; for one in flight, pick `INCLUDED` when you only need inclusion and want the earliest return, or `FINAL` when the real question is "is it done?" + +Two handoffs from here: + +- **Submitting live?** [`broadcast_tx_async`](/rpc/transaction/broadcast-tx-async) returns the hash as soon as the node accepts the payload — track separately with `tx`. [`send_tx`](/rpc/transaction/send-tx) submits and blocks on your chosen `wait_until` in a single call. +- **Need the receipt tree, not just outcomes?** `tx` already includes `receipts_outcome`; widen to [`EXPERIMENTAL_tx_status`](/rpc/transaction/experimental-tx-status) only when you also need the raw receipt records. + +## Tip Block Inspection + +### Describe the first action of the first transaction at the current tip + +A NEAR block is a header over N shard chunks, not a flat list of transactions. `block` returns chunk headers; the transactions live one level down, inside `chunk`. There's no `block → tx` shortcut — the block doesn't carry transaction hashes, so `tx` (which needs a hash) doesn't enter this flow at all. The canonical walk is `status` → `block` → `chunk`, skipping empty chunks along the way. Most chunks in a tip block are empty — their `tx_root` is the sentinel `11111111111111111111111111111111` — so the selector has to filter. + +```bash +EMPTY_TX_ROOT=11111111111111111111111111111111 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +BLOCK_HASH="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data '{"jsonrpc":"2.0","id":"fastnear","method":"status","params":[]}' \ + | jq -r '.result.sync_info.latest_block_hash')" + +CHUNK_HASH="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg block_hash "$BLOCK_HASH" '{ + jsonrpc:"2.0",id:"fastnear",method:"block",params:{block_id:$block_hash} + }')" \ + | jq -r --arg empty "$EMPTY_TX_ROOT" ' + first(.result.chunks[] | select(.tx_root != $empty) | .chunk_hash) // empty')" + +if [ -z "$CHUNK_HASH" ]; then + echo "tip block had no transactions in any chunk — rerun on the next head" +else + curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg chunk_hash "$CHUNK_HASH" '{ + jsonrpc:"2.0",id:"fastnear",method:"chunk",params:{chunk_id:$chunk_hash} + }')" \ + | jq '{ + chunk_shard: .result.header.shard_id, + chunk_height: .result.header.height_included, + first_tx: { + hash: .result.transactions[0].hash, + signer_id: .result.transactions[0].signer_id, + receiver_id: .result.transactions[0].receiver_id + }, + first_action: ( + .result.transactions[0].actions[0] as $a + | if ($a | type) == "string" then {kind: $a} + elif $a.FunctionCall then {kind: "FunctionCall", method_name: $a.FunctionCall.method_name} + else {kind: ($a | keys[0])} end + ) + }' +fi +``` + +A live run returns the current tip's first chunk, first transaction, and first action — often a `FunctionCall` on a bridge or tg-bot contract (mainnet is active). A tip block can be valid and still have no transactions in any chunk, which is why the empty branch stays; it's the honest answer for a quiet moment on the network. + +## Account and Key Mechanics + +### Identify function-call keys you might want to remove + +Every wallet, gateway, and dapp session you sign into tends to leave behind a function-call key. Most of them you'll never use again. `view_access_key_list` returns every key on an account; the structure of the nonce tells you which ones are stale. + +New keys start at `block_height * 10^6` and the value increments by one per transaction the key signs, so: + +- `nonce / 10^6` → the block the key was added at +- `nonce % 10^6` → the number of times the key has been used + +Any key with `tx_count: 0` was created and never used — the clearest candidate for cleanup. Keys scoped to a contract you no longer interact with are the next tier. The filter below narrows to `social.near`, but `RECEIVER_ID` is the only line that changes to audit a different contract. + +```bash +ACCOUNT_ID=root.near +RECEIVER_ID=social.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.mainnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_access_key_list",account_id:$account_id,finality:"final"} + }')" \ + | jq --arg receiver "$RECEIVER_ID" ' + { + total_keys: (.result.keys | length), + fcks_for_receiver: [ + .result.keys[] + | select((.access_key.permission | type) == "object") + | select(.access_key.permission.FunctionCall.receiver_id == $receiver) + | { + public_key, + added_at_block: (.access_key.nonce / 1000000 | floor), + tx_count: (.access_key.nonce % 1000000), + method_names: (.access_key.permission.FunctionCall.method_names | if . == [] then "ANY" else . end), + allowance: (.access_key.permission.FunctionCall.allowance // "unlimited") + } + ] | sort_by(.tx_count) + }' +``` + +For `root.near`, this returns 235 total keys, including 34 function-call keys for `social.near`; 21 of those were created and never used (`tx_count: 0`) and are prime cleanup candidates. `method_names: "ANY"` means the key can call any method on `social.near`; a narrowed list like `["find_grants", "insert_grant", "delete_grant"]` means the key was scoped to one dapp's write surface. + +To remove one, sign a `DeleteKey` action with a **full-access** key (a function-call key cannot authorize `DeleteKey`) and submit via [`send_tx`](/rpc/transaction/send-tx). Re-run the query to confirm the key is gone. + +## Contract Reads and Raw State + +### Read a contract's storage without executing it + +A view method like `get_num` still makes the node load the contract's wasm and run it. If you already know the storage key, `view_state` returns the raw serialized bytes directly — no execution, and no dependency on whether the contract exposes a getter for that field at all. + +Contracts built with `near-sdk-rs` store the top-level `#[near_bindgen]` struct under the key `STATE`. Pass `STATE` as `prefix_base64` (`U1RBVEU=` is base64 for those four ASCII bytes) and the node returns the serialized value. + +```bash +CONTRACT_ID=counter.near-examples.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +RAW_B64="$(curl -s "https://rpc.testnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg contract "$CONTRACT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_state",account_id:$contract,prefix_base64:"U1RBVEU=",finality:"final"} + }')" \ + | jq -r '.result.values[0].value')" + +DECODED_I8="$(python3 -c "import base64; print(int.from_bytes(base64.b64decode('$RAW_B64'),'little',signed=True))")" + +jq -n --arg raw "$RAW_B64" --argjson val "$DECODED_I8" '{raw_bytes_base64: $raw, decoded_i8: $val}' +``` + +For the live counter, this returns `"CQ=="` — one byte `0x09`, decoded as signed i8 to `9`. That's the same number `get_num` would return, but read straight from the trie without running any contract code. `signed=True` matters: a negative counter serializes as `"/w=="` (byte `0xff` → i8 `-1`, not u8 `255`). + +Reach for `view_state` when a contract doesn't expose a view method for the data you need, or when you want a key family the contract doesn't publish. For most reads `call_function` is still lower ceremony. If the question turns historical rather than current, widen to [KV FastData API](/fastdata/kv). + +## NEAR Social and BOS Exact Reads + +These stay on exact SocialDB reads and on-chain readiness checks until the question turns historical. + +### Can this account still publish to NEAR Social right now? + +`social.near` knows two things a wallet UI can only guess at: how much storage each account has left, and whether a delegated signer is allowed to write under it. Two view calls collapse the readiness question to a single boolean. + +```bash +ACCOUNT_ID=root.near # account you're writing under +SIGNER_ACCOUNT_ID=root.near # account signing the transaction +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +STORAGE_ARGS_B64="$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id:$account_id}' | base64 | tr -d '\n')" + +STORAGE="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$STORAGE_ARGS_B64" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"get_account_storage",args_base64:$args,finality:"final"} + }')" \ + | jq '.result.result | implode | fromjson')" + +if [ "$SIGNER_ACCOUNT_ID" = "$ACCOUNT_ID" ]; then + PERMISSION=true +else + PERM_ARGS_B64="$(jq -nc --arg pred "$SIGNER_ACCOUNT_ID" --arg key "$ACCOUNT_ID" '{predecessor_id:$pred,key:$key}' | base64 | tr -d '\n')" + PERMISSION="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$PERM_ARGS_B64" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"is_write_permission_granted",args_base64:$args,finality:"final"} + }')" \ + | jq '.result.result | implode | fromjson')" +fi + +jq -n --argjson storage "$STORAGE" --argjson permission "$PERMISSION" \ + --arg account_id "$ACCOUNT_ID" --arg signer "$SIGNER_ACCOUNT_ID" '{ + account_id: $account_id, + signer_account_id: $signer, + storage: $storage, + permission_granted: $permission, + ready_to_publish: (($storage.available_bytes // 0) > 0 and $permission) + }' +``` + +For `root.near` signing under itself, this returns `storage: {used_bytes: 136245, available_bytes: 42484}`, `permission_granted: true` (owner write), and `ready_to_publish: true`. If `storage` comes back `null` or `available_bytes: 0`, the account needs a `storage_deposit` on `social.near` before any new write can stick. If the signer differs from the target, the permission branch asks `is_write_permission_granted({predecessor_id, key})` — the same on-chain answer a dapp sees before writing on a user's behalf. See the [SocialDB API](https://github.com/NearSocial/social-db#api) for the full contract surface. + +### What does `mob.near/widget/Profile` actually contain right now? + +SocialDB stores BOS widgets as `/widget/` keys on `social.near`. One `keys` call with the `BlockHeight` return type returns the catalog plus per-widget last-write anchors; one `get` call returns the exact source. + +```bash +ACCOUNT_ID=mob.near +WIDGET_NAME=Profile +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +KEYS_ARGS="$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + keys: [($account_id + "/widget/*")], + options: {return_type: "BlockHeight"} +}' | base64 | tr -d '\n')" + +curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$KEYS_ARGS" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"keys",args_base64:$args,finality:"final"} + }')" \ + | jq --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" ' + .result.result | implode | fromjson | .[$account_id].widget as $map + | { + total_widgets: ($map | length), + most_recently_written: ($map | to_entries | sort_by(-.value) | .[0:5] | map({widget: .key, last_write_block: .value})), + target_last_write_block: $map[$widget] + }' + +GET_ARGS="$(jq -nc --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" '{ + keys: [($account_id + "/widget/" + $widget)] +}' | base64 | tr -d '\n')" + +curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$GET_ARGS" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"get",args_base64:$args,finality:"final"} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" ' + .result.result | implode | fromjson | .[$account_id].widget[$widget] | split("\n")[0:20] | join("\n")' +``` + +For `mob.near`, the catalog shows 264 widgets; `Profile` last wrote at block `86494825` — years ago, stable since — and the source begins with `const accountId = props.accountId ?? context.accountId;`. The `BlockHeight` return type costs nothing extra and turns the key listing into a cheap staleness check. Keep the last-write block if you later want to prove *which transaction* wrote this version — hand it to [Advanced SocialDB write lookup](/tx/socialdb-proofs). + +## Common mistakes + +- Starting in RPC when the user really wants a holdings summary or indexed history. +- Forgetting to switch from regular RPC to archival RPC for older state. +- Treating docs UI browser auth as a production backend pattern. +- Staying in low-level transaction status calls after the question becomes forensic or history-oriented. + +## Related guides + +- [RPC Reference](/rpc) +- [Auth & Access](/auth) +- [FastNear API](/api) +- [Transactions API](/tx) +- [Choosing the Right Surface](/agents/choosing-surfaces) +- [Agent Playbooks](/agents/playbooks) diff --git a/docs/rpc/index.md b/docs/rpc/index.md index 602f4a9..0857c1b 100644 --- a/docs/rpc/index.md +++ b/docs/rpc/index.md @@ -44,6 +44,10 @@ https://archival-rpc.testnet.fastnear.com - [`send_tx`](/rpc/transaction/send-tx) for transaction submission; [`tx`](/rpc/transaction/tx-status) for execution status. - [`validators`](/rpc/validators/validators-current) for the current epoch's validator set. +## Need a workflow? + +Use [RPC Examples](/rpc/examples) for worked examples like exact state checks, block inspection, contract view calls, and send-and-confirm transaction work. + ## Use RPC when - You want protocol-native request and response shapes. diff --git a/docs/rpc/protocol/chunk-by-block-shard.mdx b/docs/rpc/protocol/chunk-by-block-shard.mdx index 69e4fe1..34f1767 100644 --- a/docs/rpc/protocol/chunk-by-block-shard.mdx +++ b/docs/rpc/protocol/chunk-by-block-shard.mdx @@ -12,5 +12,8 @@ import FastnearDirectOperation from '@site/src/components/FastnearDirectOperatio `chunk` request type +Use this when you know the block and shard coordinates and want to inspect exactly what that shard executed in that block. + +This is the most natural RPC route for cross-shard debugging because it answers the practical question “what did shard X execute in block Y?” The response gives the chunk header plus the transactions and receipts in that shard-local execution unit. If you already have the exact chunk hash, use [Chunk by Hash](/rpc/protocol/chunk-by-hash). If you want the fuller per-shard envelope with state changes and produced receipts, use [Block Shard](/neardata/block-shard). For a worked tracing example, see [RPC Examples](/rpc/examples). diff --git a/docs/rpc/protocol/chunk-by-hash.mdx b/docs/rpc/protocol/chunk-by-hash.mdx index 7a55e5f..0edee84 100644 --- a/docs/rpc/protocol/chunk-by-hash.mdx +++ b/docs/rpc/protocol/chunk-by-hash.mdx @@ -12,5 +12,8 @@ import FastnearDirectOperation from '@site/src/components/FastnearDirectOperatio `chunk` request type +Use this when another tool has already given you an exact chunk hash and you want the canonical protocol chunk: the header, the transactions included there, and the incoming receipts that shard executed in that block. + +On NEAR, a signed transaction can hand off into receipts that keep running on later chunks or different shards. This route is the right fit once the chunk hash is already known from a block summary, a tracing workflow, or a proof/debugging flow. If you know the block and shard coordinates instead, use [Chunk by Block and Shard](/rpc/protocol/chunk-by-block-shard). For a worked receipt-to-chunk tracing example, see [RPC Examples](/rpc/examples). diff --git a/docs/snapshots/examples.mdx b/docs/snapshots/examples.mdx new file mode 100644 index 0000000..ec32531 --- /dev/null +++ b/docs/snapshots/examples.mdx @@ -0,0 +1,66 @@ +--- +sidebar_label: Examples +slug: /snapshots/examples +title: Snapshot Examples +description: Task-first snapshot recovery examples for optimized, standard, and archival node recovery. +displayed_sidebar: snapshotsSidebars +page_actions: + - markdown +--- + +## Mainnet recovery paths + +Pick one class — optimized `fast-rpc`, standard RPC, or archival — and run only that path's commands. Mixing classes produces inconsistent node data. + +FastNear maintains these helpers for recovery speed. If your environment requires change review, fetch the script and inspect it before running it (instead of piping straight to `bash`). + +### Optimized mainnet `fast-rpc` + +```bash +DATA_PATH=~/.near/data + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone.sh \ + | DATA_PATH="$DATA_PATH" CHAIN_ID=mainnet RPC_TYPE=fast-rpc bash +``` + +### Standard mainnet RPC + +```bash +DATA_PATH=~/.near/data + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone.sh \ + | DATA_PATH="$DATA_PATH" CHAIN_ID=mainnet bash +``` + +### Mainnet archival + +Archival needs two downloads that must come from the *same* snapshot cut. Capture one `LATEST` value and reuse it for both hot and cold data — mixing heights yields an internally inconsistent dataset and surprises nearcore at config time. + +```bash +HOT_DATA_PATH=~/.near/data +COLD_DATA_PATH=/mnt/hdds/cold-data + +LATEST="$(curl -s "https://snapshot.neardata.xyz/mainnet/archival/latest.txt")" +echo "Latest archival mainnet snapshot block: $LATEST" + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh \ + | DATA_TYPE=hot-data DATA_PATH="$HOT_DATA_PATH" CHAIN_ID=mainnet BLOCK="$LATEST" bash + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh \ + | DATA_TYPE=cold-data DATA_PATH="$COLD_DATA_PATH" CHAIN_ID=mainnet BLOCK="$LATEST" bash +``` + +## Common mistakes + +- Using snapshot docs when the task is really about reading chain data. +- Choosing archival recovery when a standard or optimized RPC path would do. +- Forgetting the hot/cold storage split for archival data. +- Jumping into commands before deciding the network and node goal. + +## Related guides + +- [Snapshots overview](/snapshots) +- [Mainnet snapshots](/snapshots/mainnet) +- [Testnet snapshots](/snapshots/testnet) +- [RPC Reference](/rpc) +- [NEAR Data API](/neardata) diff --git a/docs/snapshots/index.mdx b/docs/snapshots/index.mdx index d9d1bb8..d76da71 100644 --- a/docs/snapshots/index.mdx +++ b/docs/snapshots/index.mdx @@ -62,6 +62,10 @@ sudo -v ; curl https://rclone.org/install.sh | sudo bash See nearcore for node requirements, and fastnear/static for the snapshot download script source used by these guides. +## Need a workflow? + +Use [Snapshot Examples](/snapshots/examples) for worked operator examples like choosing between optimized `fast-rpc`, standard RPC recovery, and archival hot/cold snapshot paths. + ## Choose a network
diff --git a/docs/transaction-flow/advanced-features.mdx b/docs/transaction-flow/advanced-features.mdx index 62db7b4..76ad575 100644 --- a/docs/transaction-flow/advanced-features.mdx +++ b/docs/transaction-flow/advanced-features.mdx @@ -161,22 +161,13 @@ submit(signed_tx); ### Step 3: Runtime Processing -```mermaid -sequenceDiagram - participant User as Alice (sender) - participant Relayer as Relayer - participant RT as Runtime - participant Contract as contract.near - - User->>Relayer: SignedDelegateAction - Relayer->>RT: Transaction (Delegate action) - RT->>RT: Verify delegate signature (NEP-461) - RT->>RT: Check expiration - RT->>RT: Validate access key & nonce - RT->>Contract: Execute inner actions as Alice - Contract-->>RT: Result - RT-->>Relayer: Gas refund -``` +For docs users, the relayer flow is the only part worth keeping in short-term memory: + +1. the user signs a `DelegateAction` +2. the relayer wraps and submits it +3. the runtime verifies signature, expiry, and access-key rules +4. the inner actions execute as the user +5. gas refund returns to the relayer **Source:** `runtime/runtime/src/actions.rs` @@ -415,26 +406,12 @@ pub fn on_oracle_data(&mut self) { ### Flow Diagram -```mermaid -sequenceDiagram - participant User - participant Contract - participant Oracle as Off-Chain Oracle - participant RT as Runtime - - User->>Contract: request_oracle_data("ETH/USD") - Contract->>RT: promise_yield_create() - RT-->>Contract: data_id - Contract->>Contract: Store data_id, emit event - Contract-->>User: Transaction complete (yield pending) - - Note over Oracle: Monitors events, fetches data - - Oracle->>Contract: resume_oracle(data_id, price_data) - Contract->>RT: promise_yield_resume() - RT->>Contract: on_oracle_data() callback - Contract->>Contract: Process price data -``` +For docs users, the yield/resume path is: + +1. the contract yields and gets a `data_id` +2. some external system keeps that `data_id` +3. the external system later resumes with payload data +4. the callback runs with either data or failure ## Timeout Mechanism diff --git a/docs/transaction-flow/finality.mdx b/docs/transaction-flow/finality.mdx index 88dbd40..0044c67 100644 --- a/docs/transaction-flow/finality.mdx +++ b/docs/transaction-flow/finality.mdx @@ -73,16 +73,7 @@ pub enum ExecutionStatus { A single transaction can produce many outcomes: -```mermaid -flowchart TD - TX1[Transaction Hash: TX1] --> TO[TransactionOutcome] - TO -->|status: SuccessReceiptId R1| R1[ReceiptOutcome R1] - TO -->|receipt_ids: R1, R2| R2[ReceiptOutcome R2] - R1 -->|status: SuccessValue| R3[ReceiptOutcome R3] - R1 -->|receipt_ids: R3| done1[Done] - R2 -->|status: SuccessValue| done2[Done] - R3 -->|Refund| done3[Done] -``` +For docs users, the important shape is simpler than the full outcome tree: one `tx_hash` gives you one `transaction_outcome` plus zero or more `receipts_outcome`. Your job is to combine those objects into one readable story of what happened. **Example outcome tree:** ``` @@ -138,18 +129,24 @@ pub enum FinalExecutionStatus { ## Querying Outcomes +These RPC reads work on the public FastNear RPC hosts. If `FASTNEAR_API_KEY` is already set in your shell, the snippets forward it automatically as a bearer header. + ### The `tx` RPC Method ```bash -curl -X POST https://rpc.mainnet.fastnear.com \ +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -X POST https://archival-rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": "1", "method": "tx", "params": { - "tx_hash": "6zgh2u9DqHHiXzdy9ouTP7oGky2T4nugqzqt9wJZwNFm", - "sender_account_id": "sender.near", + "tx_hash": "7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq", + "sender_account_id": "root.near", "wait_until": "FINAL" } }' diff --git a/docs/transaction-flow/foundations.mdx b/docs/transaction-flow/foundations.mdx index fb8b4f9..6066122 100644 --- a/docs/transaction-flow/foundations.mdx +++ b/docs/transaction-flow/foundations.mdx @@ -1,6 +1,6 @@ --- title: Foundations -description: Transaction structure, actions, and serialization formats in NEAR +description: Transaction fields, actions, and serialization formats that show up in RPC submission and status responses slug: /transaction-flow/foundations sidebar_position: 1 keywords: @@ -13,7 +13,7 @@ keywords: # Foundations -This section covers the fundamental building blocks of NEAR transactions: data structures, action types, account models, and serialization formats. +Use this section to understand the fields you actually see in signed transactions, RPC submission, and status responses. The goal is not to memorize internal actors; it is to recognize what the signer, receiver, nonce, block hash, and action list mean when you inspect a transaction. ## What is a Transaction? @@ -30,35 +30,17 @@ Every transaction in NEAR has these fundamental properties: The atomicity guarantee applies only within a single shard. Cross-shard operations (function calls to contracts on different shards) are executed asynchronously and do **not** have atomic semantics. See [Async Model](./async-model) for details. ::: -### The Transaction Lifecycle +### What matters for docs users ```mermaid flowchart LR - subgraph Creation - A[Client Signs Tx] - end - subgraph Submission - B[RPC Layer] - end - subgraph Validation - C[Handler Actor] - end - subgraph Network - D[P2P Forward] - end - subgraph Block Production - E[Chunk Producer] - end - subgraph Execution - F[Runtime Applies Actions] - end - A -->|base64/borsh| B - B -->|struct| C - C -->|struct| D - D -->|borsh| E - E -->|struct| F + A["SignedTransaction fields"] --> B["Submit or inspect with RPC"] + B --> C["Get tx hash and actions"] + C --> D["Interpret outcomes and receipts"] ``` +For this docs site, that is the useful mental model. The internal handoff through pools, chunk producers, and runtime matters only if it changes the meaning of a field you are already reading. + ## The SignedTransaction Data Structure The `SignedTransaction` is the fundamental unit that travels through the system. diff --git a/docs/transaction-flow/gas-economics.mdx b/docs/transaction-flow/gas-economics.mdx index f507a32..5c9b551 100644 --- a/docs/transaction-flow/gas-economics.mdx +++ b/docs/transaction-flow/gas-economics.mdx @@ -174,16 +174,12 @@ fn compute_gas_refund( ### Refund Flow -```mermaid -flowchart TD - A[Prepaid Gas] --> B[Execute Transaction] - B --> C{Gas Burnt} - C --> D[Gross Refund = Prepaid - Burnt] - D --> E[Apply NEP-536 Penalty] - E --> F[Net Refund] - F --> G[Convert to NEAR at Original Price] - G --> H[Refund Receipt to Signer] -``` +For docs users, the refund path is simpler than the runtime code: + +1. gas is prepaid up front +2. execution burns part of that gas +3. unused gas becomes a refund amount +4. the refund comes back as a later receipt ### Refund Types @@ -243,14 +239,7 @@ All unused gas is currently refunded in full. Gas price adjusts based on block utilization: -```mermaid -flowchart LR - A[Block Utilization] --> B{> 50%?} - B -->|Yes| C[Gas Price Increases] - B -->|No| D[Gas Price Decreases] - C --> E[Discourages spam] - D --> F[Encourages usage] -``` +When blocks are busier, protocol gas price rises. When blocks are quieter, it falls. For docs users, the important part is that this adjustment is protocol-driven, not a fee-bidding market. The adjustment follows an exponential smoothing algorithm bounded by protocol parameters. @@ -397,19 +386,7 @@ console.log(`Tokens burnt: ${Number(outcome.tokens_burnt) / 1e24} NEAR`); Refunds arrive as receipts in subsequent blocks: -```mermaid -sequenceDiagram - participant User - participant ShardA as Shard A - participant ShardB as Shard B - - User->>ShardA: Transaction (prepay 100 TGas) - ShardA->>ShardA: Execute (burn 30 TGas) - ShardA->>ShardB: Cross-shard receipt - ShardB->>ShardB: Execute - ShardB->>ShardA: Refund receipt (unused gas) - ShardA->>ShardA: Apply refund to User balance -``` +Refunds often land in later blocks, especially when cross-shard receipts are involved. Do not expect the account balance view to reflect them immediately at the moment the first transaction outcome appears. Don't expect instant balance updates after transaction completion. diff --git a/docs/transaction-flow/index.mdx b/docs/transaction-flow/index.mdx index 01ea783..a063ba4 100644 --- a/docs/transaction-flow/index.mdx +++ b/docs/transaction-flow/index.mdx @@ -1,6 +1,6 @@ --- title: Transaction Flow in NEAR Protocol -description: Complete guide to transaction lifecycle from JSON-RPC submission to validator execution +description: Practical guide to the user-visible stages of a NEAR transaction, from RPC submission to receipts and finality sidebar_position: 0 slug: /transaction-flow sidebar_label: Overview @@ -15,16 +15,13 @@ keywords: # Transaction Flow in NEAR Protocol -This guide traces the complete lifecycle of a transaction in NEAR Protocol, from JSON-RPC submission to validator execution. +This guide focuses on the stages a docs user can actually observe: submission, transaction status, receipt fan-out, and final outcome. It keeps protocol background only where that background changes what you should query next. ```mermaid flowchart LR - Client["Client Signs Tx"] --> RPC["RPC Layer"] - RPC --> Validation["Validation"] - Validation --> P2P["P2P Forward"] - P2P --> Pool["Transaction Pool"] - Pool --> Chunk["Chunk Producer"] - Chunk --> Runtime["Runtime Execution"] + Submit["Submit signed transaction"] --> Track["Track tx hash"] + Track --> Receipts["Inspect receipts only if needed"] + Receipts --> Final["Confirm final outcome or final state"] ``` ## Quick Reference diff --git a/docs/transaction-flow/infrastructure.mdx b/docs/transaction-flow/infrastructure.mdx index 16135e8..3b41271 100644 --- a/docs/transaction-flow/infrastructure.mdx +++ b/docs/transaction-flow/infrastructure.mdx @@ -303,7 +303,7 @@ fn account_id_to_shard_id(&self, account_id: &AccountId) -> ShardId { } ``` -**Current mainnet boundaries:** +**Example contiguous boundaries:** ``` boundary_accounts: ["aurora", "aurora-0", "kkuuue2akv_1630967379.near"] @@ -330,14 +330,7 @@ pub struct ShardLayoutV2 { Accounts map to shards based on **alphabetical ordering**: -```mermaid -flowchart LR - A[account_id] --> B{Compare to boundaries} - B -->|"< aurora"| S0[Shard 0] - B -->|">= aurora, < aurora-0"| S1[Shard 1] - B -->|">= aurora-0, < kkuuue..."| S2[Shard 2] - B -->|">= kkuuue..."| S3[Shard 3] -``` +For docs users, the exact boundary table is rarely the task. The practical takeaway is simpler: the signer account determines the first shard that sees the transaction, and subaccounts can land on a different shard than their parent because sorting uses the full account name. :::warning Account Naming Implications Alphabetical ordering uses the **full account name**. Subaccounts sort by their full name, not parent: diff --git a/docs/transaction-flow/network-blocks.mdx b/docs/transaction-flow/network-blocks.mdx index e96ebed..c0a5240 100644 --- a/docs/transaction-flow/network-blocks.mdx +++ b/docs/transaction-flow/network-blocks.mdx @@ -202,21 +202,11 @@ pub enum InsertTransactionResult { ## Round-Robin Fair Selection -When a chunk producer builds a chunk, they use a **round-robin algorithm** that gives each account a fair chance: - -```mermaid -flowchart TD - A[Start at randomized position] --> B[For each account/key group] - B --> C[Pop lowest-nonce transaction] - C --> D{Valid?} - D -->|Yes| E[Add to chunk] - D -->|No| F[Drop or skip] - E --> G{Limits reached?} - F --> G - G -->|No| H[Rotate to next group] - H --> B - G -->|Yes| I[Chunk complete] -``` +For docs users, the exact scheduler is less important than three user-visible consequences: + +- inclusion is fair rather than fee-bid driven +- transactions for the same account/key still respect nonce order +- full chunks delay inclusion instead of reordering for higher bids ### Selection Properties @@ -277,21 +267,7 @@ A chunk contains: - Gas used and limits ### Production Flow - -```mermaid -sequenceDiagram - participant BP as Block Producer - participant CP as Chunk Producer - participant Net as Network - - BP->>CP: Signal "produce chunk for shard X at height H" - CP->>CP: Select transactions from pool - CP->>CP: Execute transactions (create receipts) - CP->>CP: Create chunk header and body - CP->>BP: Send chunk - BP->>BP: Assemble block with all chunks - BP->>Net: Propagate block -``` +From a docs perspective, chunk production matters only because it determines when a transaction or receipt first becomes visible in block-scoped data. You usually do not need the producer handshake; you need the resulting block height, shard placement, and receipt timing. ### Chunk Header @@ -319,31 +295,14 @@ Once transactions become receipts, they're executed in a **strict three-phase or **Source:** `runtime/runtime/src/lib.rs`, function `process_receipts()` -```mermaid -flowchart TD - subgraph Phase1[Phase 1: LOCAL RECEIPTS] - L1[Receipts from THIS block's transactions] - L2[Order: Transaction inclusion order] - end - - subgraph Phase2[Phase 2: DELAYED RECEIPTS] - D1[Backlog from previous blocks] - D2[Order: Strict FIFO queue] - end - - subgraph Phase3[Phase 3: INCOMING RECEIPTS] - I1[Cross-shard receipts arriving THIS block] - I2[Order: Chunk order - deterministic] - end - - subgraph Phase4[Phase 4: YIELD TIMEOUTS] - Y1[NEP-519 promises that expired] - end - - Phase1 --> Phase2 - Phase2 --> Phase3 - Phase3 --> Phase4 -``` +For docs users, keep the ordering rule simpler than the runtime implementation: + +1. local receipts from this block's transactions +2. delayed receipts from older backlog +3. incoming cross-shard receipts +4. yield timeouts + +The exact phase boundary matters only when you are explaining why one receipt became visible before another. ### Phase Details diff --git a/docs/transaction-flow/reference.mdx b/docs/transaction-flow/reference.mdx index 18a0236..df80bf3 100644 --- a/docs/transaction-flow/reference.mdx +++ b/docs/transaction-flow/reference.mdx @@ -174,11 +174,17 @@ You never "call" another contract. You send them a letter and ask them to send o ### curl Examples +These RPC reads work on the public FastNear RPC hosts. If `FASTNEAR_API_KEY` is already set in your shell, the snippets forward it automatically as a bearer header. + #### Submit Transaction (Async) ```bash # Submit and get hash immediately +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + curl -X POST https://rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", @@ -194,7 +200,11 @@ curl -X POST https://rpc.mainnet.fastnear.com \ #### Submit Transaction (Wait for Final) ```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + curl -X POST https://rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", @@ -207,15 +217,19 @@ curl -X POST https://rpc.mainnet.fastnear.com \ #### Check Transaction Status ```bash -curl -X POST https://rpc.mainnet.fastnear.com \ +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -X POST https://archival-rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": "1", "method": "tx", "params": { - "tx_hash": "6zgh2u9DqHHiXzdy9ouTP7oGky2T4nugqzqt9wJZwNFm", - "sender_account_id": "sender.testnet", + "tx_hash": "7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq", + "sender_account_id": "root.near", "wait_until": "FINAL" } }' @@ -224,7 +238,11 @@ curl -X POST https://rpc.mainnet.fastnear.com \ #### View Access Key (for nonce) ```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + curl -X POST https://rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", @@ -233,8 +251,8 @@ curl -X POST https://rpc.mainnet.fastnear.com \ "params": { "request_type": "view_access_key", "finality": "final", - "account_id": "sender.testnet", - "public_key": "ed25519:DcA2MzgpJbrUATQLLceocVckhhAqrkingax4oJ9kZ847" + "account_id": "root.near", + "public_key": "ed25519:CByX7HPjgSGFi5G26zwgZGDFCFyBHvSv1fe7AFzmVe3" } }' @@ -245,7 +263,11 @@ curl -X POST https://rpc.mainnet.fastnear.com \ #### Get Recent Block Hash ```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + curl -X POST https://rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", diff --git a/docs/transaction-flow/runtime-execution.mdx b/docs/transaction-flow/runtime-execution.mdx index 261b1b2..1eb75c4 100644 --- a/docs/transaction-flow/runtime-execution.mdx +++ b/docs/transaction-flow/runtime-execution.mdx @@ -75,15 +75,12 @@ Actions execute in order within a transaction. All actions in a single transacti ### Execution Order -```mermaid -flowchart TD - A[Validate all actions] --> B{All valid?} - B -->|No| C[Return validation error] - B -->|Yes| D[Execute actions sequentially] - D --> E[Generate receipts for cross-shard effects] - E --> F[Update state] - F --> G[Return execution outcome] -``` +For docs users, the actionable model is short: + +1. validate the batch +2. execute actions in order +3. emit receipts for async work +4. return one execution outcome The detailed flow: @@ -390,15 +387,19 @@ flowchart TD Clients can poll the `tx` RPC method with `wait_until: FINAL` to get all outcomes: ```bash -curl -X POST https://rpc.mainnet.fastnear.com \ +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -X POST https://archival-rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": "1", "method": "tx", "params": { - "tx_hash": "6zgh2u9DqHHiXzdy9ouTP7oGky2T4nugqzqt9wJZwNFm", - "sender_account_id": "sender.near", + "tx_hash": "7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq", + "sender_account_id": "root.near", "wait_until": "FINAL" } }' diff --git a/docs/transfers/examples.md b/docs/transfers/examples.md new file mode 100644 index 0000000..b0235a1 --- /dev/null +++ b/docs/transfers/examples.md @@ -0,0 +1,111 @@ +--- +sidebar_label: Examples +slug: /transfers/examples +title: Transfers Examples +description: Task-first transfer examples for filtering feeds, paging, and pivoting into transaction history. +displayed_sidebar: transfersApiSidebar +page_actions: + - markdown +--- + +## Examples + +These shell examples work on the public Transfers and Transactions endpoints. If `FASTNEAR_API_KEY` is already set in your shell, the snippets forward it as a bearer header automatically. + +### What's this account's recent transfer activity? + +`/v0/transfers` with just `account_id` and `desc: true` returns the most recent transfers touching that account across every asset type, both directions mixed. Each row already carries `human_amount`, `asset_id`, and `transaction_id`, so the feed doubles as a quick activity scan before you reach for filters. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id: $account_id, desc: true, limit: 5}')" \ + | jq '{ + recent: [.transfers[] | { + block_height, + asset_id, + human_amount, + other_account_id, + transfer_type, + tx: .transaction_id + }] + }' +``` + +For `root.near`, the latest rows mix `FtTransfer` and `MtTransfer` assets. `asset_id` uses NEP-standard URIs (`native:near`, `nep141:...`, `nep245:...`), so one field tells you which standard to reach for next. Positive `human_amount` means the account received; negative means it sent. `other_account_id: null` is normal for multi-token shapes where the counterparty sits inside a contract boundary rather than as a top-level account. + +### Filter and page a transfer feed for one account + +`/v0/transfers` returns a filtered feed plus a `resume_token` you replay with *unchanged* filters to keep paging. Each row already carries `human_amount`, `usd_amount`, `transaction_id`, and `receipt_id`, so most audit questions land without a second call. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +FEED="$(curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + account_id: $account_id, + direction: "receiver", + asset_id: "native:near", + min_amount: "1000000000000000000000000", + desc: true, + limit: 10 + }')")" + +echo "$FEED" | jq '{ + resume_token, + transfers: [.transfers[] | {block_height, amount, human_amount, usd_amount, other_account_id, transaction_id, receipt_id}] +}' +``` + +For the pinned account this returns recent incoming native-NEAR transfers of at least 1 NEAR — sample rows are native transfers from `escrow.ai.near` with USD already computed. To page, resend the same body with a top-level `resume_token: ""`; changing any other filter invalidates the token. + +When one row needs its execution anchor, take its `receipt_id` straight to `/v0/receipt`: + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +FEED="$(curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + account_id: $account_id, + direction: "receiver", + asset_id: "native:near", + min_amount: "1000000000000000000000000", + desc: true, + limit: 10 + }')")" +RECEIPT_ID="$(echo "$FEED" | jq -r '.transfers[0].receipt_id')" + +curl -s "https://tx.main.fastnear.com/v0/receipt" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg receipt_id "$RECEIPT_ID" '{receipt_id: $receipt_id}')" \ + | jq '.receipt | {receipt_id, transaction_hash, receiver_id, predecessor_id, tx_block_height, is_success}' +``` + +That's the same handoff covered in [Turn one receipt ID into a readable transaction story](/tx/examples#receipt-id-to-readable-story) — one call gets the receipt and its full parent transaction. + +## Common mistakes + +- Using Transfers API when the user really wants balances, holdings, or account summaries. +- Treating transfer history as full execution history. +- Reusing a `resume_token` with different filters. + +## Related guides + +- [Transfers API](/transfers) +- [Transactions API](/tx) +- [FastNear API](/api) +- [Choosing the Right Surface](/agents/choosing-surfaces) +- [Agent Playbooks](/agents/playbooks) diff --git a/docs/transfers/index.md b/docs/transfers/index.md index 0260fbf..90fd054 100644 --- a/docs/transfers/index.md +++ b/docs/transfers/index.md @@ -66,6 +66,10 @@ When that happens, widen to [Transactions API](/tx) or [FastNear API](/api) inst - [Query Transfers](/transfers/query) for the account-centric feed with direction, asset, amount, and time filters +## Need a workflow? + +Use [Transfers API Examples](/transfers/examples) for worked examples like narrow transfer searches, `resume_token` pagination, and escalation into broader transaction investigation. + ## Troubleshooting ### I need full transaction metadata diff --git a/docs/tx/berry-club.mdx b/docs/tx/berry-club.mdx new file mode 100644 index 0000000..45cfa35 --- /dev/null +++ b/docs/tx/berry-club.mdx @@ -0,0 +1,152 @@ +--- +sidebar_label: Berry Club +slug: /tx/examples/berry-club +title: "Berry Club: Read the live board, then reconstruct one era" +description: "Read the live Berry Club board with RPC get_lines, then use Transactions API to reconstruct one older era." +displayed_sidebar: transactionsApiSidebar +page_actions: + - markdown +keywords: + - Berry Club + - FastNear + - Transactions API + - RPC + - get_lines + - draw + - pixel board +--- + +import Link from '@site/src/components/LocalizedLink'; +import BerryClubLiveBoard from '@site/src/components/BerryClubLiveBoard'; + +{/* FASTNEAR_AI_DISCOVERY: This walkthrough shows the shortest useful Berry Club flow: read the live board with RPC get_lines, then use Transactions API only when you need to reconstruct one older era from draw calls. */} + +# Berry Club: Read the live board, then reconstruct one era + +Use this walkthrough when the live board is easy to read, but you need one historical reconstruction path behind it. + +Start with the live board. If that already answers the question, stop there. + +Only switch to Transactions API when the question becomes historical: “what did Berry Club look like during one older era, and which `draw` calls made it look that way?” + +These shell examples work against the public RPC and Transactions endpoints. If `FASTNEAR_API_KEY` is already set in your shell, the FastNear calls will forward it automatically as a bearer header. + + + +## 1. Read the live board + +This is the shortest useful read: + +```bash +ARGS_BASE64="$(jq -nc '{lines: [range(0;50)]}' | base64 | tr -d '\n')" +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "{ + \"jsonrpc\": \"2.0\", + \"id\": \"berry-live-board\", + \"method\": \"query\", + \"params\": { + \"request_type\": \"call_function\", + \"finality\": \"final\", + \"account_id\": \"berryclub.ek.near\", + \"method_name\": \"get_lines\", + \"args_base64\": \"$ARGS_BASE64\" + } + }" | jq '.result | {block_height, line_count: (.result | implode | fromjson | length)}' +``` + +That gives you the current 50x50 board from the contract itself. The only decode step is turning each returned base64 line into 50 pixel colors. + +## 2. Reconstruct one older era + +When you need history, keep the flow short: + +1. bound one era +2. list candidate `draw` transactions for `berryclub.ek.near` +3. hydrate those hashes +4. replay the `pixels` arrays oldest-first + +This example uses a narrow window around block `97601515`: + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://tx.main.fastnear.com/v0/account \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{ + "account_id": "berryclub.ek.near", + "is_function_call": true, + "is_receiver": true, + "is_real_receiver": true, + "from_tx_block_height": 97576515, + "to_tx_block_height": 97601516, + "desc": false, + "limit": 200 + }' | jq '.account_txs | map({transaction_hash, tx_block_height}) | .[-5:]' +``` + +If you do not know the window yet, `/v0/blocks` can help you choose one first. It is not part of the core Berry Club flow. + +Hydrate the candidate hashes and keep only top-level `draw` calls: + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://tx.main.fastnear.com/v0/transactions \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{ + "tx_hashes": [ + "Hq5qwsuiM2emJrqczWM9awCa7o6sTBYqYpcifUX2SUhQ", + "8tBip5M2TrozhSyepAA3tYXpyKooi5t7b9c64wXjFvfL" + ] + }' | jq '.transactions[] + | select(.transaction.receiver_id == "berryclub.ek.near") + | .transaction.actions[]?.FunctionCall + | select(.method_name == "draw") + | {method_name, args: (.args | @base64d | fromjson)}' +``` + +Replay the `pixels` arrays oldest-first: + +```javascript +const board = Array.from({ length: 50 }, () => Array(50).fill(0)); + +for (const drawTx of drawTransactionsOldestFirst) { + for (const pixel of drawTx.args.pixels) { + if (pixel.x < 0 || pixel.x >= 50 || pixel.y < 0 || pixel.y >= 50) { + continue; + } + + board[pixel.y][pixel.x] = pixel.color; + } +} +``` + +That is the whole historical pattern. Berry Club does not expose a ready-made “board at block N” endpoint, so older eras come from replaying `draw` writes. + +## Related guides + +- RPC: call_function +- Transactions API: Account History +- Transactions API: Transactions by Hash diff --git a/docs/tx/examples.md b/docs/tx/examples.md new file mode 100644 index 0000000..e7be78b --- /dev/null +++ b/docs/tx/examples.md @@ -0,0 +1,254 @@ +--- +sidebar_label: Examples +slug: /tx/examples +title: Transactions Examples +description: Task-first transaction investigations for hashes, receipts, async failures, and callbacks. +displayed_sidebar: transactionsApiSidebar +page_actions: + - markdown +--- + +## Start Here + +All shell examples below work on the public Transactions API hosts as-is. If `FASTNEAR_API_KEY` is set in your shell, they add it as a bearer header automatically; if it is unset, they fall back to the public unauthenticated path. + +### I have one transaction hash. What happened? + +Paste the hash into `POST /v0/transactions` and one response usually holds the whole story. + +```bash +TX_HASH=7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq '{ + hash: .transactions[0].transaction.hash, + signer_id: .transactions[0].transaction.signer_id, + receiver_id: .transactions[0].transaction.receiver_id, + included_block_height: .transactions[0].execution_outcome.block_height, + actions: (.transactions[0].transaction.actions | map(if type == "string" then . else keys[0] end)), + first_receipt_id: .transactions[0].execution_outcome.outcome.status.SuccessReceiptId, + receipt_count: (.transactions[0].receipts | length) + }' +``` + +For the pinned hash, `root.near` sent a single `Transfer` to `escrow.ai.near` in block `188976785`, handing off into receipt `B8QzHQZ6VnUVy8zaVXCEkWuSs7MPb34yoHYixZV3Zdj1`. When `receipt_count > 1` or the next question is about receipt-level behavior, jump to [Which receipt emitted this log or event?](#which-receipt-emitted-this-log-or-event) or [`POST /v0/receipt`](/tx/receipt). + +### Which receipt emitted this log or event? + +List every logged receipt in the transaction with a flag for whether its logs contain your fragment. The match is provable rather than guessed: this pinned tx logs a `Transfer` on one receipt and a `Refund` on another, and only the `Refund` side flips to `true`. + +```bash +TX_HASH=2KhhB1uDScGCFQfVchep7DiZTGTxMcgfUYHNzwf5e6uL +LOG_FRAGMENT=Refund +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg fragment "$LOG_FRAGMENT" ' + [ + .transactions[0].receipts[] + | select((.execution_outcome.outcome.logs | length) > 0) + | { + receipt_id: .receipt.receipt_id, + receiver_id: .receipt.receiver_id, + method_name: (.receipt.receipt.Action.actions[0] + | if type == "string" then . else (.FunctionCall.method_name // keys[0]) end), + matches_fragment: any(.execution_outcome.outcome.logs[]?; contains($fragment)), + logs: .execution_outcome.outcome.logs + } + ]' +``` + +The `Refund` fragment attributes to receipt `9sLHQpaGz3NnMNMn8zGrDUSyktR1q6ts2otr9mHkfD1w` on `wrap.near`, method `ft_resolve_transfer`. Receipt logs live on receipts, not on the transaction, so this single pass is enough — no deeper async trace needed. + +### Turn one receipt ID into a readable transaction story {#receipt-id-to-readable-story} + +`POST /v0/receipt` returns the receipt record **and** its full parent transaction in one response, so a single call covers the whole story — no follow-up `/v0/transactions` fetch needed. + +```bash +RECEIPT_ID=B8QzHQZ6VnUVy8zaVXCEkWuSs7MPb34yoHYixZV3Zdj1 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/receipt" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg receipt_id "$RECEIPT_ID" '{receipt_id: $receipt_id}')" \ + | jq '{ + receipt: { + receipt_id: .receipt.receipt_id, + type: .receipt.receipt_type, + is_success: .receipt.is_success, + receipt_block: .receipt.block_height, + tx_block: .receipt.tx_block_height, + predecessor_id: .receipt.predecessor_id, + receiver_id: .receipt.receiver_id, + transaction_hash: .receipt.transaction_hash + }, + parent_transaction: { + signer_id: .transaction.transaction.signer_id, + receiver_id: .transaction.transaction.receiver_id, + action_types: (.transaction.transaction.actions | map(if type == "string" then . else keys[0] end)) + } + }' +``` + +For the pinned receipt, this returns an `Action` receipt from `root.near` to `escrow.ai.near` that executed successfully in block `188976786`, one block after its parent tx `7ZKnhzt2…` landed — a single `Transfer` (3.5 NEAR, visible as `3500000000000000000000000` yocto in the raw `.transaction.transaction.actions`). If the parent tx becomes the interesting anchor, you already have the hash — reuse it with [I have one transaction hash. What happened?](#i-have-one-transaction-hash-what-happened). + +## Failure and Async + +### Prove that one failed action reverted the whole batch + +One batch submitted `CreateAccount → Transfer → AddKey → FunctionCall` and the final call hit a missing method. The indexed tx record already carries the ordered batch *and* the exact receipt-level failure, so one call answers "what was tried and what broke"; a `view_account` check then proves the earlier actions rolled back. + +```bash +TX_HASH=CrhH3xLzbNwNMGgZkgptXorwh8YmqxRGuA6Mc11MkU6M +NEW_ACCOUNT_ID=rollback-mo4vmkig.temp.mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.test.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq '{ + action_types: (.transactions[0].transaction.actions | map(if type == "string" then . else keys[0] end)), + final_method: .transactions[0].transaction.actions[3].FunctionCall.method_name, + tx_handoff: .transactions[0].execution_outcome.outcome.status, + receipt_failure: ( + first( + .transactions[0].receipts[] + | select(.execution_outcome.outcome.status.Failure != null) + | .execution_outcome.outcome.status.Failure.ActionError + ) + ) + }' +``` + +The tx-level status is `SuccessReceiptId` — the transaction successfully handed its batched actions off to a receipt. The failure lives one layer down on that receipt: `index: 3` (the `FunctionCall`), kind `CodeDoesNotExist` on `rollback-mo4vmkig.temp.mike.testnet`. `SuccessReceiptId` on the tx outcome means "handoff worked," not "everything finished" — a real trap if you only look at the tx-level status. + +Now prove the earlier actions rolled back by asking for the account the batch *tried* to create: + +```bash +NEW_ACCOUNT_ID=rollback-mo4vmkig.temp.mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.testnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$NEW_ACCOUNT_ID" '{ + jsonrpc: "2.0", id: "fastnear", method: "query", + params: {request_type: "view_account", account_id: $account_id, finality: "final"} + }')" \ + | jq '{error: .error.cause.name, requested_account_id: .error.cause.info.requested_account_id}' +``` + +`UNKNOWN_ACCOUNT` is the proof. If `CreateAccount` had stuck, `view_account` would resolve; because it does not, the earlier `Transfer` and `AddKey` from the same batched receipt did not stick either. + +### When a tx looks successful, what actually happened? + +A tx's outer `execution_outcome.outcome.status` reports `SuccessReceiptId` whenever the first receipt handoff worked — it says nothing about whether downstream receipts succeeded or whether the origin callback ran. One pipeline over `/v0/transactions` answers all three questions at once. + +```bash +TX_HASH=2KhhB1uDScGCFQfVchep7DiZTGTxMcgfUYHNzwf5e6uL +ORIGIN_CONTRACT_ID=wrap.near +CALLBACK_METHOD=ft_resolve_transfer +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg origin "$ORIGIN_CONTRACT_ID" --arg callback "$CALLBACK_METHOD" '{ + outer: { + method: .transactions[0].transaction.actions[0].FunctionCall.method_name, + tx_handoff: (.transactions[0].execution_outcome.outcome.status | keys[0]) + }, + callback: { + expected_on: $origin, + method: $callback, + ran: any( + .transactions[0].receipts[]; + .receipt.receiver_id == $origin + and (.receipt.receipt.Action.actions[0].FunctionCall.method_name // "") == $callback + ) + }, + descendant_failures: [ + .transactions[0].receipts[] + | select(.execution_outcome.outcome.status.Failure != null) + | { + receiver_id: .receipt.receiver_id, + method: (.receipt.receipt.Action.actions[0].FunctionCall.method_name // "system"), + cause: .execution_outcome.outcome.status.Failure + } + ] + }' +``` + +For the pinned tx, `outer.method` is `ft_transfer_call` and `outer.tx_handoff` is `SuccessReceiptId` — the tx kicked off its first receipt cleanly, and read alone you'd call it a win. `descendant_failures` tells a second story: `ft_on_transfer` on `v2.ref-finance.near` panicked with `E51: contract paused` — the DEX was paused when this swap ran, so it couldn't accept the wrapped NEAR. `callback.ran: true` tells a third: `wrap.near`'s `ft_resolve_transfer` fired anyway. A downstream failure never prevents the origin contract's callback from running — that's the mechanism by which NEP-141 refunds the sender when the receiver rejects. + +Receipt success is not transitive. A protocol can hand off cleanly and still see the detached work fail later; the origin callback runs either way. Read these three fields together and the async story is legible without chasing the receipt chain by hand. To surface the `Refund` log line itself, pivot to [Which receipt emitted this log or event?](#which-receipt-emitted-this-log-or-event). + +### Pair one OutLayer request with its TEE worker resolution + +[OutLayer](https://outlayer.fastnear.com) splits one logical call across two transactions: a user signs `request_execution` on `outlayer.near`, an Intel TDX worker runs the requested WASM off-chain, then `worker.outlayer.near` submits the result with `submit_execution_output_and_resolve`. Both halves carry the same `request_id` — passing the two tx hashes to `/v0/transactions` in one call and extracting that field from each proves the pair. + +```bash +REQUEST_TX=BZDQAxEdpQ9wUGXmXTa2APwFLDTTqTy5ucrBPsfgZeyz +WORKER_TX=3NYD4Mkn5cwkuVkGP9PPoiJ9PB5Vr7v6r8CwSswtHVA3 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg a "$REQUEST_TX" --arg b "$WORKER_TX" '{tx_hashes: [$a, $b]}')" \ + | jq '[ + .transactions[] + | { + role: (if .transaction.actions[0].FunctionCall.method_name == "request_execution" + then "request" else "worker" end), + hash: .transaction.hash, + signer: .transaction.signer_id, + method: .transaction.actions[0].FunctionCall.method_name, + block: .execution_outcome.block_height, + request_id: ( + if .transaction.actions[0].FunctionCall.method_name == "request_execution" + then (.receipts[0].execution_outcome.outcome.logs[] | select(startswith("EVENT_JSON")) + | sub("EVENT_JSON:"; "") | fromjson | .data[0].request_data | fromjson | .request_id) + else (.receipts[0].receipt.receipt.Action.actions[0].FunctionCall.args + | @base64d | fromjson | .request_id) + end + ) + } + ]' +``` + +Both rows carry `request_id: 1868`, confirming the pair. The request half, signed by `retrorn.near` in block `194832281`, lives in an `EVENT_JSON:` log on its receipt (that's NEAR's yield/resume pattern — the on-chain promise pauses while the TDX worker runs). The worker half lands 11 blocks later with `submit_execution_output_and_resolve`, signed by `worker.outlayer.near`, and its `request_id` decodes straight out of the base64 `FunctionCall.args`. The same two payloads also carry the richer fingerprint — `sender_id`, `project_id`, `code_hash`, `resources_used.instructions`, `resources_used.time_ms`, encrypted-result byte count — if you want to audit what actually ran; this minimal pipeline just confirms they belong together. `/v0/transactions` serves historical pairs indefinitely, so you don't need archival RPC weeks later. + +## Common mistakes + +- Trying to submit a transaction from the history API instead of raw RPC. +- Using Transactions API when the user only wants current balances or holdings. +- Dropping to raw RPC before indexed history has answered the readable "what happened?" question. + +## Related guides + +- [Transactions API](/tx) +- [RPC Reference](/rpc) +- [FastNear API](/api) +- [NEAR Data API](/neardata) +- [Berry Club: live board and one historical reconstruction path](/tx/examples/berry-club) +- [Advanced SocialDB write lookup](/tx/socialdb-proofs) +- [Choosing the Right Surface](/agents/choosing-surfaces) +- [Agent Playbooks](/agents/playbooks) diff --git a/docs/tx/index.md b/docs/tx/index.md index 1c8f4ce..3d661cd 100644 --- a/docs/tx/index.md +++ b/docs/tx/index.md @@ -49,6 +49,10 @@ https://tx.test.fastnear.com - [Receipt lookup](/tx/receipt) for execution-flow investigation. - [Block range](/tx/blocks) when you want a bounded history scan. +## Need a workflow? + +Use [Transactions API Examples](/tx/examples) for worked examples like transaction lookups, receipt investigation, account activity, and block-window history. + ## Troubleshooting ### I expected to submit a transaction here diff --git a/docs/tx/socialdb-proofs.mdx b/docs/tx/socialdb-proofs.mdx new file mode 100644 index 0000000..7774b9a --- /dev/null +++ b/docs/tx/socialdb-proofs.mdx @@ -0,0 +1,162 @@ +--- +slug: /tx/socialdb-proofs +title: Advanced SocialDB Write Lookup +description: One small advanced playbook for starting from a readable SocialDB value and recovering the write transaction behind it. +displayed_sidebar: transactionsApiSidebar +page_actions: + - markdown +--- + +# Advanced SocialDB Write Lookup + +Use this page only when the starting point is already a readable SocialDB value from `api.near.social` and the next question is historical write lookup. + +These shell steps work against the public SocialDB and FastNear endpoints. If `FASTNEAR_API_KEY` is already set in your shell, the FastNear calls will forward it automatically as a bearer header. + +For FastNear-first jobs, start with [Transactions Examples](/tx/examples). Come here only when the question has become "which write made this readable SocialDB value true?" + +## Canonical example: prove that `root.near` set `profile.name` to `Illia` + +Use this when the readable fact is already "the current `profile.name` is `Illia`" and the remaining question is which write made that field true. + +This is the one SocialDB nuance worth keeping: for historical proof, the field-level `:block` is usually the right bridge, not the parent object's `:block`. + +For this live anchor: + +- current `profile.name`: `Illia` +- field-level SocialDB write block: `75590392` +- receipt ID: `GYvnvBxWA46UGa3aGEkqUBeT7hxhVXk2iZScJFZWU8Se` +- originating transaction hash: `7HtFWv51k5Bispmh1WYPbAVkxr2X4AL6n98DhcQwVw7w` +- outer transaction block: `75590391` + +### Shell walkthrough + +1. Read the field from NEAR Social and capture the field-level write block. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name + +PROFILE="$(curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')")" + +echo "$PROFILE" | jq --arg account_id "$ACCOUNT_ID" '{ + current_name: .[$account_id].profile.name[""], + field_block_height: .[$account_id].profile.name[":block"], + parent_profile_block_height: .[$account_id].profile[":block"] +}' + +PROFILE_BLOCK_HEIGHT="$(echo "$PROFILE" | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]')" +``` + +2. Reuse that field-level block in FastNear block receipts and recover the receipt plus tx hash. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +PROFILE_BLOCK_HEIGHT="$( + curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]' +)" +BLOCK_RECEIPTS="$(curl -s "https://tx.main.fastnear.com/v0/block" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --argjson block_id "$PROFILE_BLOCK_HEIGHT" '{ + block_id: $block_id, + with_transactions: false, + with_receipts: true + }')")" + +echo "$BLOCK_RECEIPTS" | jq --arg account_id "$ACCOUNT_ID" '{ + profile_receipt: ( + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | {receipt_id, transaction_hash, block_height, tx_block_height} + ) + ) +}' + +PROFILE_TX_HASH="$(echo "$BLOCK_RECEIPTS" | jq -r --arg account_id "$ACCOUNT_ID" ' + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | .transaction_hash + )')" +``` + +3. Reuse that tx hash in `POST /v0/transactions` and decode the SocialDB write payload. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +PROFILE_BLOCK_HEIGHT="$( + curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]' +)" +PROFILE_TX_HASH="$( + curl -s "https://tx.main.fastnear.com/v0/block" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --argjson block_id "$PROFILE_BLOCK_HEIGHT" '{ + block_id: $block_id, + with_transactions: false, + with_receipts: true + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" ' + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | .transaction_hash + )' +)" +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$PROFILE_TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg account_id "$ACCOUNT_ID" '{ + transaction: { + hash: .transactions[0].transaction.hash, + signer_id: .transactions[0].transaction.signer_id, + receiver_id: .transactions[0].transaction.receiver_id, + included_block_height: .transactions[0].execution_outcome.block_height + }, + write_proof: ( + .transactions[0].receipts[0].receipt.receipt.Action.actions[0].FunctionCall + | (.args | @base64d | fromjson | .data[$account_id].profile) as $profile + | { + method_name, + profile_name: $profile.name, + image_fields: (($profile.image // {}) | keys), + linktree_keys: (($profile.linktree // {}) | keys) + } + ) + }' +``` + +That is the whole lookup pattern: readable value, field-level block, receipt bridge, and transaction payload. + +The same bridge works for other readable SocialDB values too: + +- follow edge variant: `root.near -> mob.near`, block `79152039`, tx `DvNoqtDrruhmcq7mPpxdFacph2ZCqSzMFF5ZqMRFG78q` +- widget source variant: `root.near/widget/Profile`, block `76029540`, tx `ELS3DrE4Upoc91ZnBh4thVugxCUBAbaLFB4nyKsoyRNP` + +The key idea does not change: start from the readable value and its write block, recover the `*.near -> social.near` receipt from the block, then decode the `social.near set` payload from the originating transaction. diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/agents/auth-for-agents.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/agents/auth-for-agents.mdx index 035ae2c..9c1af09 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/agents/auth-for-agents.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/agents/auth-for-agents.mdx @@ -12,7 +12,7 @@ page_actions: Агенты должны аутентифицироваться в FastNear так же, как это делают продовые бэкенды. Не переносите браузерно-демонстрационный режим из UI документации в агента, воркера или среду автоматизации. -Один API-ключ FastNear работает во всех RPC и API-эндпоинтах. Многие публичные чтения работают и без ключа. Для агента важнее не само наличие аутентификации, а где живёт учётная запись, как она прикрепляется к запросам и как не допустить её утечки в промпты, логи или состояние браузера. +Один API-ключ FastNear работает во всех RPC и API-эндпоинтах. Для агента важнее не само наличие аутентификации, а где живёт учётная запись, как она прикрепляется к запросам и как не допустить её утечки в промпты, логи или состояние браузера. ## Если нужно только правило @@ -36,8 +36,8 @@ page_actions: | Способ | Используйте, когда... | Заметки | | --- | --- | --- | -| `Authorization: Bearer ${API_KEY}` | HTTP-клиентом или бэкендом управляете вы | Лучшее значение по умолчанию для агентов. Меньше шансов утечь в логи URL, аналитику или скопированные ссылки. | -| `?apiKey=${API_KEY}` | используется простой curl или система, которой сложно выставлять заголовки | Тоже допустимо, но URL обычно дальше путешествуют через логи и инструменты. Применяйте осознанно. | +| `Authorization: Bearer ${FASTNEAR_API_KEY}` | HTTP-клиентом или бэкендом управляете вы | Лучшее значение по умолчанию для агентов. Меньше шансов утечь в логи URL, аналитику или скопированные ссылки. | +| `?apiKey=${FASTNEAR_API_KEY}` | используется простой curl или система, которой сложно выставлять заголовки | Тоже допустимо, но URL обычно дальше путешествуют через логи и инструменты. Применяйте осознанно. | Если есть выбор — используйте заголовочную форму. @@ -68,13 +68,13 @@ const response = await fetch('https://rpc.mainnet.fastnear.com', { }); ``` -## Когда аутентификации не хватает +## Если в среде выполнения нет ключа -Многие публичные эндпоинты FastNear по-прежнему доступны на чтение без ключа. Если агент может ответить на вопрос пользователя через публичный трафик — делайте так. +Агенту по умолчанию стоит стартовать с настроенным API-ключом FastNear. Некоторые публичные чтения могут сработать и без него, но это не должно быть базовой рабочей моделью. -Когда ключ нужен для повышенных лимитов, платного доступа или аутентифицированного трафика: +Если в настроенной среде ключа пока нет: -- подскажите пользователю создать или забрать ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com) +- подскажите пользователю создать или забрать ключ в [FastNear Dashboard](https://dashboard.fastnear.com) - попросите настроить его в переменной окружения, менеджере секретов или конфигурации бэкенда - не просите вставлять сырой ключ в чат, чтобы агент «носил» его с собой diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/agents/index.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/agents/index.mdx index 4e60c6d..bd1e365 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/agents/index.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/agents/index.mdx @@ -25,6 +25,7 @@ page_actions: - Используйте индексированные API, когда пользователю нужен ответ в продуктовой форме — балансы, активы, история аккаунта или история переводов. - Используйте [Справочник RPC](/rpc), когда пользователю нужны канонические поля на уровне протокола, вызовы контрактов или отправка транзакций. +- Если вы используете размещённый JS-рантайм на [js.fastnear.com](https://js.fastnear.com), начинайте с низкоуровневых методов вроде `near.view`, `near.queryAccount` и `near.tx.*`, а к `near.recipes.*` обращайтесь только тогда, когда task helper действительно является самым коротким путём к ответу. - Используйте [NEAR Data API](/neardata), когда вопрос касается свежих оптимистичных или финализированных блоков и явного опроса. - Используйте [Снапшоты](/snapshots/) для операторских сценариев, а не для чтения прикладных данных. - Один API-ключ FastNear работает и для RPC, и для API-эндпоинтов. @@ -98,20 +99,24 @@ page_actions: ## Аутентифицируйтесь один раз, используйте везде -Публичные эндпоинты часто работают и без ключа. Добавьте ключ, если нужны повышенные лимиты, единая аутентифицированная модель или платные сценарии. Один и тот же ключ работает со всеми API FastNear выше, включая обычные и архивные RPC-хосты; передавайте его либо в HTTP-заголовке, либо в URL-параметре: +Начните с API-ключа FastNear и используйте его во всех API FastNear выше, включая обычные и архивные RPC-хосты. Передавайте его либо в HTTP-заголовке, либо в URL-параметре: ```bash title="Заголовок Authorization" +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + curl "https://rpc.mainnet.fastnear.com" \ - -H "Authorization: Bearer ${API_KEY}" \ + -H "Authorization: Bearer $FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` ```bash title="URL-параметр" -curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + +curl "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" ``` -Получить ключ: [dashboard.fastnear.com](https://dashboard.fastnear.com). Операционный режим для неинтерактивных сред: [Аутентификация для агентов](/agents/auth) — ключи должны жить в переменных окружения или менеджере секретов, а не в браузерном хранилище, логах чатов или промптах. Полный сценарий и детали заголовков: [Аутентификация и доступ](/auth). +Получите API-ключ в [FastNear Dashboard](https://dashboard.fastnear.com). Операционный режим для неинтерактивных сред: [Аутентификация для агентов](/agents/auth) — ключи должны жить в переменных окружения или менеджере секретов, а не в браузерном хранилище, логах чатов или промптах. Полный сценарий и детали заголовков: [Аутентификация и доступ](/auth). ## Как вынимать чистую документацию в промпт diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/api/examples.md b/i18n/ru/docusaurus-plugin-content-docs/current/api/examples.md new file mode 100644 index 0000000..6868726 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/api/examples.md @@ -0,0 +1,206 @@ +--- +sidebar_label: Examples +slug: /api/examples +title: "Примеры API" +description: "Практические примеры FastNear API: поиск аккаунта по ключу, просмотр активов и классификация стейкинга." +displayed_sidebar: fastnearApiSidebar +page_actions: + - markdown +--- + +## Примеры + +Все shell-примеры ниже работают на публичных FastNear API-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### Свести один аккаунт за один вызов + +`/v1/account/{id}/full` — это агрегатор аккаунтов в FastNear API: один вызов собирает NEAR-состояние аккаунта, каждый FT-контракт, которого он касался, каждую NFT-коллекцию, которую он получил, и каждый валидаторский пул, в который делегировал. Если у вас уже есть `account_id`, это самый быстрый ответ на вопрос «что это за аккаунт?». + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + account_id, + near_balance_yocto: .state.balance, + ft_contracts: (.tokens | length), + nft_contracts: (.nfts | length), + staking_pool_contracts: (.pools | length) + }' +``` + +Для `root.near`: 150 FT-контрактов в списке, 102 NFT-коллекции, 2 валидаторских пула. Одни только счётчики контрактов говорят, что это оживлённый mainnet-аккаунт. Все примеры ниже погружаются в какую-то одну из этих поверхностей — начинайте отсюда, когда на руках только ID аккаунта. + +### Определить аккаунт по публичному ключу и сразу получить сводку + +Найдите, какому аккаунту принадлежит ключ, и прочитайте его активы за один следующий запрос. + +```bash +PUBLIC_KEY='ed25519:CCaThr3uokqnUs6Z5vVnaDcJdrfuTpYJHJWcAGubDjT' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +LOOKUP="$(curl -s "https://api.fastnear.com/v1/public_key/$(jq -rn --arg k "$PUBLIC_KEY" '$k | @uri')" \ + "${AUTH_HEADER[@]}")" + +echo "$LOOKUP" | jq '{matched: (.account_ids | length), account_ids}' + +ACCOUNT_ID="$(echo "$LOOKUP" | jq -r '.account_ids[0]')" + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq '{account_id, state, tokens: (.tokens|length), nfts: (.nfts|length), pools: (.pools|length)}' +``` + +Если `matched` больше 1, переключайтесь на [V1 Public Key Lookup All](/api/v1/public-key-all) и пройдитесь по каждому найденному аккаунту. + +### Сколько NEAR на этом аккаунте реально доступно к переводу? + +Состояние аккаунта NEAR делится на три ведра, которые UI кошельков обычно сливает в одно: `balance` — это свободная часть (не в стейкинге), `locked` — NEAR, привязанный к валидаторскому стейку или lockup-контракту, а `storage_bytes` подразумевает ещё отдельную долю, пришпиленную к trie по текущей ставке 10^19 yoctoNEAR за байт. Один pipeline над `/full` разводит их по полкам. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq ' + (.state.balance | tonumber) as $amount + | (.state.locked | tonumber) as $locked + | (.state.storage_bytes * 10000000000000000000) as $pinned + | 1e24 as $ynear + | { + account_id, + near: { + total_owned: (($amount + $locked) / $ynear), + unstaked: ($amount / $ynear), + stake_or_lockup: ($locked / $ynear), + pinned_to_storage: ($pinned / $ynear), + spendable: (($amount - $pinned) / $ynear) + } + }' +``` + +Для `root.near`: ~3914.67 NEAR всего, всё в свободной части, ~0.28677 NEAR закреплено за 28,677 байтами on-chain-состояния, ~3914.38 NEAR доступно к переводу. Новым аккаунтам это особенно заметно — свежесозданный именованный аккаунт ~182 байта «съедает» ~0.00182 NEAR под storage, и именно поэтому CLI-утилиты не дают отправить полный баланс. + +Наведите тот же pipeline на валидаторский пул вроде `astro-stakers.poolv1.near`, и пропорции перевернутся: ~730 тыс. свободных, ~27.68 млн в `locked`. Этот `locked` — собственный протокольный валидаторский стейк пула, а не средства делегатов (те учитываются внутри состояния контракта пула). Одно и то же поле означает разное на разных типах аккаунтов. + +jq считает в IEEE-754 double, поэтому NEAR-значения выше — только для отображения; для точной бухгалтерии сохраняйте сами yocto-строки. + +### Когда в этом аккаунте что-либо последний раз менялось? + +У каждой записи в массивах `tokens`, `nfts` и `pools` внутри `/full` есть собственное `last_update_block_height` — блок, в котором индексер последний раз видел изменение этой строки для этого аккаунта. Максимум по всем трём массивам даёт дешёвый сигнал «последняя активность» без похода в Transactions API. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq ' + [ + (.tokens // [])[].last_update_block_height, + (.nfts // [])[].last_update_block_height, + (.pools // [])[].last_update_block_height + ] as $heights + | ($heights | map(select(. != null))) as $tracked + | { + account_id, + total_entries: ($heights | length), + tracked_entries: ($tracked | length), + most_recent_block: ($tracked | max), + oldest_tracked_block: ($tracked | min) + }' +``` + +Для `root.near` это возвращает 254 записи по FT-, NFT- и pool-контрактам, 158 с отслеживаемым блоком и самый свежий блок `194301659`. Этого уже достаточно, чтобы понять, что кошелёк живой, не заходя в историю транзакций. + +Это правильный вопрос для «был ли этот кошелёк недавно активен?» или «двигалось ли что-то после блока X?» — дёшево, один запрос, без истории транзакций. Чтобы достать саму транзакцию, вызвавшую последнее изменение, расширяйте поверхность до [Transactions API](/tx). Записи с `last_update_block_height: null` относятся ко времени до per-row-отслеживания индексером (обычно старые airdrops) и здесь игнорируются, а не считаются свежими. + +### Показать NFT-коллекции этого кошелька от конкретного издателя + +Имена аккаунтов на NEAR кодируют иерархию: `mint.sharddog.near` — это подаккаунт `sharddog.near`, который, в свою очередь, — подаккаунт `near`. Издатели, выпускающие несколько NFT-коллекций, обычно разворачивают каждую как отдельный подаккаунт, поэтому один фильтр по суффиксу над NFT-списком аккаунта вытаскивает всё опубликованное под одним деревом — без внешнего реестра коллекций. + +```bash +ACCOUNT_ID=root.near +PUBLISHER=sharddog.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/nft" \ + "${AUTH_HEADER[@]}" \ + | jq --arg publisher "$PUBLISHER" ' + ("." + $publisher) as $suffix + | { + account_id: .account_id, + publisher: $publisher, + collections: [ + .tokens[] + | select(.contract_id | endswith($suffix)) + | { + contract_id, + last_update_block_height, + status: (if .last_update_block_height == null then "dormant" else "active" end) + } + ] | sort_by(.last_update_block_height // 0) + }' +``` + +Для `root.near` и `sharddog.near` это возвращает четыре контракта-подаккаунта: `ndcconstellationnft`, `mint`, `harvestmoon` и `claim`. Только у `claim` есть ненулевой `last_update_block_height` (`131402024`), так что именно этот контракт явно менял позицию кошелька. Остальные — спящие, что типично для одноразовых drop-контрактов, в которые аккаунт что-то получил и больше не возвращался. + +Поменяйте `PUBLISHER` на любой аккаунт, чтобы сфокусировать фильтр на другом дереве издателя. + +### Показывает ли кошелёк прямой стейкинг, liquid staking-токены или оба варианта? + +Прямые позиции в пулах лежат на `/staking`; liquid staking-токены (stNEAR, LiNEAR и т. п.) лежат на `/ft` как обычные FT. Прочитайте оба эндпоинта и классифицируйте кошелёк — `root.near` оказывается `mixed`. + +```bash +ACCOUNT_ID=root.near +LIQUID_PROVIDERS_JSON='["meta-pool.near","lst.rhealab.near","linear-protocol.near"]' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +STAKING="$(curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/staking" \ + "${AUTH_HEADER[@]}")" +FT="$(curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/ft" \ + "${AUTH_HEADER[@]}")" + +jq -n \ + --argjson staking "$STAKING" \ + --argjson ft "$FT" \ + --argjson providers "$LIQUID_PROVIDERS_JSON" ' + ($staking.pools // []) as $direct + | (($ft.tokens // []) | map(select(.contract_id as $id | $providers | index($id)))) as $liquid + | { + classification: ( + if ($direct|length)>0 and ($liquid|length)>0 then "mixed" + elif ($direct|length)>0 then "direct_only" + elif ($liquid|length)>0 then "liquid_only" + else "no_visible_staking_position" end + ), + direct_pools: ($direct | map(.pool_id)), + liquid_tokens: ($liquid | map({contract_id, balance})) + }' +``` + +Классификатор знает только то, чему вы его научили — расширяйте `LIQUID_PROVIDERS_JSON` по мере появления новых liquid staking-продуктов и рассматривайте результат как наблюдательный, а не исчерпывающий. + +## Частые ошибки + +- Сразу идти в широкий снимок аккаунта, когда пользователя интересует только одна категория активов. +- Использовать FastNear API, хотя пользователю нужны точные поля RPC или права доступа. +- Оставаться на страницах сводок по аккаунту, когда вопрос уже стал вопросом об истории транзакций. + +## Связанные страницы + +- [FastNear API](/api) +- [API Reference](/api/reference) +- [RPC Reference](/rpc) +- [Transactions API](/tx) +- [Choosing the Right Surface](/agents/choosing-surfaces) +- [Agent Playbooks](/agents/playbooks) diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/api/index.md b/i18n/ru/docusaurus-plugin-content-docs/current/api/index.md index 92ad506..5bfb13a 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/api/index.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/api/index.md @@ -54,6 +54,10 @@ https://test.api.fastnear.com - [V1 поиск по публичному ключу](/api/v1/public-key) — когда нужно определить аккаунт по ключу. - [V1 топ держателей FT](/api/v1/ft-top) — для представлений распределения токенов. +## Нужен сценарий? + +Используйте [примеры FastNear API](/api/examples) для практических примеров: сводки по аккаунтам, определения аккаунта по ключу и перехода к узким представлениям активов. + ## Устранение неполадок ### Мне нужно только одно низкоуровневое значение из состояния цепочки diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/auth/index.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/auth/index.mdx index 7b20fc5..201629d 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/auth/index.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/auth/index.mdx @@ -32,19 +32,21 @@ import IconExternalLink from '@theme/Icon/ExternalLink'; # Аутентификация и доступ -Один API-ключ FastNear работает и для [RPC](/rpc), и для [API-эндпоинтов](/api). Многие публичные чтения работают и без него, но когда ключ нужен, модель остаётся простой: используйте один и тот же ключ везде и передавайте его либо через заголовок `Authorization: Bearer`, либо как URL-параметр `?apiKey=`. +Один API-ключ FastNear работает и для [RPC](/rpc), и для [API-эндпоинтов](/api). Держите модель аутентификации простой: используйте один и тот же ключ везде и передавайте его либо через заголовок `Authorization: Bearer`, либо как URL-параметр `?apiKey=`. Та же модель действует и на обычных, и на архивных RPC-хостах. Хранение ключа в браузере для UI документации — это удобство документации, а не продовый шаблон. -Войдите на dashboard.fastnear.com, чтобы получить ключ, и отправляйте его в каждом запросе одним из способов ниже. +Получите ключ в FastNear Dashboard и отправляйте его в каждом запросе одним из способов ниже. Страницы с интерактивными примерами также поддерживают `Copy example URL`, чтобы делиться уже заполненными запросами. Общие URL примеров выполняются автоматически при загрузке, когда в них есть состояние операции, а сохранённые API-ключи и токены никогда не включаются в такие общедоступные URL документации. ## Через заголовок Authorization ```bash +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + curl "https://rpc.mainnet.fastnear.com" \ - -H "Authorization: Bearer ${API_KEY}" \ + -H "Authorization: Bearer $FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` @@ -52,7 +54,9 @@ curl "https://rpc.mainnet.fastnear.com" \ ## Через URL-параметр `?apiKey=` ```bash -curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" \ +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + +curl "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/fastdata/kv/examples.md b/i18n/ru/docusaurus-plugin-content-docs/current/fastdata/kv/examples.md new file mode 100644 index 0000000..4656e25 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/fastdata/kv/examples.md @@ -0,0 +1,108 @@ +--- +sidebar_label: Examples +slug: /fastdata/kv/examples +title: "Примеры KV FastData" +description: "Практические примеры KV FastData: точные ключи, scoped-записи, история ключа и переход к точному состоянию." +displayed_sidebar: kvFastDataSidebar +page_actions: + - markdown +--- + +## Примеры + +Все shell-примеры ниже работают на публичных KV FastData-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### Проверить один точный ключ и сразу посмотреть его историю + +Если контракт, `predecessor_id` и точный ключ уже известны, начинайте с узкого запроса. `latest` отвечает на вопрос о текущем состоянии, а `history` показывает, менялась ли именно эта строка со временем. + +```bash +CURRENT_ACCOUNT_ID=social.near +PREDECESSOR_ID=james.near +KEY='graph/follow/sleet.near' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +ENCODED_KEY="$(jq -rn --arg key "$KEY" '$key | @uri')" + +LATEST="$(curl -s "https://kv.main.fastnear.com/v0/latest/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}")" + +echo "$LATEST" | jq '{ + latest: ( + .entries[0] + | { + current_account_id, + predecessor_id, + block_height, + key, + value + } + ) +}' + +curl -s "https://kv.main.fastnear.com/v0/history/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{writes: [.entries[] | {block_height, value}]}' +``` + +Для точного ключа вроде этого follow-edge `latest` даёт текущее индексированное значение одной строкой, а `history` показывает, была ли запись однократной или переключалась со временем. Начинайте отсюда, когда путь в storage уже известен; расширяйтесь до выборок по `predecessor_id` только тогда, когда нужно не доказательство, а поиск. + +### Посмотреть индексированные записи одного `predecessor_id` и сузиться до изменившегося ключа + +`all-by-predecessor` возвращает последние индексированные записи одного аккаунта по каждому контракту, которого он касался. Выберите интересный ключ и прогоните его через `history`, чтобы увидеть, как эта строка менялась со временем. + +```bash +PREDECESSOR_ID=jemartel.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +FIRST="$(curl -s "https://kv.main.fastnear.com/v0/all/$PREDECESSOR_ID" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{"include_metadata":true,"limit":10}')" + +echo "$FIRST" | jq '{ + page_token, + entries: [.entries[] | {current_account_id, predecessor_id, block_height, key, value, tx_hash}] +}' +``` + +Для `jemartel.near` в выдаче смешиваются подтверждение идентичности `account_id` на `contextual.near` и серия добавлений `graph/follow/*` в тот же контракт. `tx_hash` в каждой строке — это прямой переход в [/tx/examples](/tx/examples#у-меня-один-хеш-транзакции-что-произошло), если нужна полная история транзакции за любой записью. + +Поднимите самую свежую строку и прогоните её через `history`: + +```bash +PREDECESSOR_ID=jemartel.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +FIRST="$(curl -s "https://kv.main.fastnear.com/v0/all/$PREDECESSOR_ID" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{"include_metadata":true,"limit":10}')" + +CURRENT_ACCOUNT_ID="$(echo "$FIRST" | jq -r '.entries[0].current_account_id')" +EXACT_KEY="$(echo "$FIRST" | jq -r '.entries[0].key')" +ENCODED_KEY="$(jq -rn --arg key "$EXACT_KEY" '$key | @uri')" + +curl -s "https://kv.main.fastnear.com/v0/history/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{entries: [.entries[] | {block_height, value}]}' +``` + +Для строки `account_id` `history` возвращает одну запись на блоке `185965311` со значением `"jemartel.near:mainnet"` — подтверждение идентичности держится, стабильно с того блока. KV сохраняет каждую запись одинаково: у тихого ключа — одна строка, у активного — много, форма та же, без агрегации. + +## Частые ошибки + +- Начинать с широких выборок по аккаунту или предшественнику, когда точный ключ уже известен. +- Использовать KV FastData, когда пользователю на самом деле нужны балансы или активы. +- Путать индексированную историю с точным текущим состоянием в цепочке. +- Переиспользовать токен пагинации или менять фильтры прямо во время просмотра. + +## Связанные страницы + +- [KV FastData API](/fastdata/kv) +- [RPC Reference](/rpc) +- [FastNear API](/api) +- [Choosing the Right Surface](/agents/choosing-surfaces) +- [Agent Playbooks](/agents/playbooks) diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/fastdata/kv/index.md b/i18n/ru/docusaurus-plugin-content-docs/current/fastdata/kv/index.md index 4e9293f..dcefef7 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/fastdata/kv/index.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/fastdata/kv/index.md @@ -22,6 +22,37 @@ https://kv.main.fastnear.com https://kv.test.fastnear.com ``` +## Быстрый старт + +Если вы уже знаете один точный ключ, начните с последней индексированной строки и остановитесь, как только она ответит на вопрос. + +```bash +CURRENT_ACCOUNT_ID=social.near +PREDECESSOR_ID=james.near +KEY='graph/follow/sleet.near' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +ENCODED_KEY="$(jq -rn --arg key "$KEY" '$key | @uri')" + +curl -s "https://kv.main.fastnear.com/v0/latest/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + latest: ( + .entries[0] + | { + current_account_id, + predecessor_id, + block_height, + key, + value + } + ) + }' +``` + +Это самый узкий полезный KV-запрос: один точный ключ и одна последняя индексированная строка. Если следующий вопрос уже звучит как «как этот ключ менялся со временем?», переходите к [истории по точному ключу](/fastdata/kv/get-history-key) или к более подробным [примерам KV FastData](/fastdata/kv/examples). + ## Используйте этот API, когда - нужно последнее индексированное состояние по одному ключу или известному семейству ключей @@ -51,6 +82,10 @@ https://kv.test.fastnear.com - [Всё по `predecessor_id`](/fastdata/kv/all-by-predecessor) или [История по `predecessor_id`](/fastdata/kv/history-by-predecessor) — когда правильная область — `predecessor_id` - [Пакетный поиск по ключам](/fastdata/kv/multi) — когда уже известно несколько точных ключей +## Нужен сценарий? + +Используйте [примеры KV FastData](/fastdata/kv/examples) для практических примеров: поиска по точному ключу, истории ключей, анализа по `predecessor_id` и перехода к каноническому RPC. + ## Рабочий цикл по умолчанию 1. Выберите самую узкую область, подходящую под вопрос пользователя. diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/index.md b/i18n/ru/docusaurus-plugin-content-docs/current/index.md index 49a0a18..04de47a 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/index.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/index.md @@ -54,7 +54,7 @@ import Link from '@site/src/components/LocalizedLink';

- Сначала возьмите ключ — войдите на [dashboard.fastnear.com](https://dashboard.fastnear.com) через Google или email, получите бесплатные стартовые кредиты и подключайте месячную подписку или бессрочные резервные кредиты только тогда, когда понадобятся повышенные лимиты. + Получите API-ключ на dashboard.fastnear.com и используйте его во всех запросах к FastNear из одного и того же рабочего окружения.

@@ -172,7 +172,7 @@ import Link from '@site/src/components/LocalizedLink';
Ключи и оплата - Dashboard + FastNear Dashboard

Войдите, создайте ключи и переходите на сценарии с более высокими лимитами, когда понадобится.

diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/neardata/block-chunk.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/neardata/block-chunk.mdx index 5987549..9adf91f 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/neardata/block-chunk.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/neardata/block-chunk.mdx @@ -1,6 +1,6 @@ --- title: "Чанк блока" -description: "Получите один чанк из финализированного блока." +description: "Получите облегчённое представление чанка одного шарда для финализированного блока." slug: /neardata/block-chunk hide_table_of_contents: true --- @@ -9,5 +9,8 @@ import FastnearDirectOperation from '@site/src/components/FastnearDirectOperatio # Чанк блока +Это облегчённое представление одного шарда для финализированного блока: заголовок чанка, включённые транзакции для этого шарда и входящие квитанции, которые он исполнил. + +Используйте этот маршрут, когда нужен взгляд на исполнение одного шарда без более широкого представления всего шарда. Он хорошо подходит для трассировки, индексации и аналитики, когда нужно только само содержимое чанка. Если ещё нужны изменения состояния и квитанции, которые это исполнение произвело, переходите к [Шарду блока](/neardata/block-shard). За готовым сценарием, где квитанция доводится до конкретного чанка, переходите в [Примеры RPC](/rpc/examples). diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/neardata/block-shard.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/neardata/block-shard.mdx index a71dac0..72c42d3 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/neardata/block-shard.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/neardata/block-shard.mdx @@ -1,6 +1,6 @@ --- title: "Шард блока" -description: "Получите один шард из финализированного блока." +description: "Получите более полное представление одного шарда для финализированного блока." slug: /neardata/block-shard hide_table_of_contents: true --- @@ -9,5 +9,8 @@ import FastnearDirectOperation from '@site/src/components/FastnearDirectOperatio # Шард блока +Используйте этот маршрут, когда данных одного чанка уже недостаточно и нужно более полное представление одного шарда для финализированного блока. + +Этот маршрут идёт на шаг шире, чем [Чанк блока](/neardata/block-chunk): помимо самого содержимого чанка, вы ещё видите изменения состояния на шарде и квитанции, которые это исполнение произвело. Поэтому этот маршрут лучше подходит для отладки, индексаторов и аналитики, когда важны итоги исполнения, а не только включённые транзакции и входящие квитанции. За готовым сценарием, который начинается с транзакции и заканчивается конечным чанком, переходите в [Примеры RPC](/rpc/examples). diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/neardata/examples.md b/i18n/ru/docusaurus-plugin-content-docs/current/neardata/examples.md new file mode 100644 index 0000000..b371522 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/neardata/examples.md @@ -0,0 +1,148 @@ +--- +sidebar_label: Examples +slug: /neardata/examples +title: "Примеры NEAR Data" +description: "Практические примеры NEAR Data: живой мониторинг, optimistic-проверки и доказательство на уровне shard." +displayed_sidebar: nearDataApiSidebar +page_actions: + - markdown +--- + +## Примеры + +NEAR Data возвращает каждый блок полностью гидратированным одним JSON-документом — header плюс per-shard chunks, receipts, результаты исполнения и state changes, — так что один `curl` уже даёт всё необходимое, чтобы отфильтровать нужный контракт без второго запроса. + +Все shell-примеры ниже работают на публичных NEAR Data-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### На каком блоке NEAR сейчас? + +`/v0/last_block/final` отдаёт 302-редирект на текущий финализированный блок. Прежде чем фильтровать по конкретному контракту, полезно увидеть, как выглядит один блок на уровне протокола: транзакции приходят с разбивкой по shard, поэтому общее число транзакций в блоке — это сумма по shards, а не одно поле верхнего уровня. + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + height: .block.header.height, + timestamp_nanosec: .block.header.timestamp_nanosec, + txs_per_shard: [.shards[] | {shard_id, tx_count: (.chunk.transactions | length)}], + total_txs: ([.shards[].chunk.transactions[]?] | length) + }' +``` + +Живой блок показывает 9 shards и горсть транзакций, распределённых по ним — большинство shards в любом блоке пустые, а активность концентрируется на тех shards, где живут загруженные контракты. `timestamp_nanosec` — это Unix-время в наносекундах (делите на 1e9, чтобы получить секунды). С этим одним вызовом у вас уже есть всё необходимое для дальнейшего копания — примеры фильтрации ниже просто применяют jq к тому же ответу. + +### Был ли мой контракт затронут в последнем финализированном блоке? + +`/v0/last_block/final` отдаёт 302-редирект на текущий финализированный блок. Контракт может проявиться либо в `transactions` chunk (когда он `receiver_id`), либо в `receipts` (когда прилетает cross-shard-вызов), поэтому один проход jq по shards покрывает оба случая. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" \ + | jq --arg contract "$TARGET_CONTRACT" '{ + height: .block.header.height, + contract: $contract, + touched_shards: [ + .shards[] | { + shard_id, + txs: [.chunk.transactions[]? | select(.transaction.receiver_id == $contract) | .transaction.hash], + receipts: [.chunk.receipts[]? | select(.receiver_id == $contract) | .receipt_id] + } | select((.txs | length) + (.receipts | length) > 0) + ] + }' +``` + +`touched_shards: []` — полный ответ для тихого блока. Непустой список называет shards, где контракт появился, и отдаёт конкретные `tx`-хеши или `receipt_id` — передавайте хеш в [Transactions API](/tx), когда нужна человекочитаемая история. Receipts без парных `txs` — это нормально: cross-contract-вызов приходит как incoming receipt в этом блоке, даже если исходная транзакция была раньше. + +### Увидел ли я активность в optimistic-режиме, и догнала ли её finality? + +Optimistic-блоки ходят по `/v0/block_opt/{height}` примерно на секунду впереди `/v0/block/{height}`. Цикл мониторинга может действовать по optimistic-сигналу и ожидать, что тот же ответ придёт на финализированный эндпоинт через один блок — если только стресс сети не расширит разрыв, и тогда финализированный fetch вернёт `null`, а вы подождёте. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +count_touches() { + jq --arg contract "$1" ' + [.shards[] + | ([.chunk.transactions[]? | select(.transaction.receiver_id == $contract)] | length) + + ([.chunk.receipts[]? | select(.receiver_id == $contract)] | length)] + | add // 0' +} + +OPT_LOCATION="$( + curl -s -D - -o /dev/null "${AUTH_HEADER[@]}" "https://mainnet.neardata.xyz/v0/last_block/optimistic" \ + | awk 'tolower($1) == "location:" {print $2}' | tr -d '\r' +)" +OPT_HEIGHT="${OPT_LOCATION##*/}" + +echo "optimistic @ $OPT_HEIGHT: $(curl -s "https://mainnet.neardata.xyz$OPT_LOCATION" \ + "${AUTH_HEADER[@]}" | count_touches "$TARGET_CONTRACT") touches" +FINAL="$(curl -s "https://mainnet.neardata.xyz/v0/block/$OPT_HEIGHT" \ + "${AUTH_HEADER[@]}")" +if [ "$(printf '%s' "$FINAL" | jq 'type')" = '"null"' ]; then + echo "finalized @ $OPT_HEIGHT: not caught up yet" +else + echo "finalized @ $OPT_HEIGHT: $(printf '%s' "$FINAL" | count_touches "$TARGET_CONTRACT") touches" +fi +``` + +На здоровом mainnet оба счётчика совпадают в пределах секунды. Ценность — в самом шаблоне: optimistic-поток даёт ответ, на который можно реагировать сразу, а финализированный приходит через блок как надёжное подтверждение. + +### Какой shard действительно изменил состояние моего контракта? + +В большинстве финализированных блоков нет мутации состояния ни для одного конкретного контракта — активность разрежена и привязана к shard. Идите назад от финализированной головы, пока состояние контракта реально не изменится, и откройте этот shard для payload мутации. Вызов уровня блока говорит, *на каком* shard это случилось; вызов уровня shard — *как*. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +HEAD="$(curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" | jq '.block.header.height')" +FOUND_HEIGHT="" +FOUND_SHARD="" + +for OFFSET in $(seq 0 15); do + H=$((HEAD - OFFSET)) + SHARD="$(curl -s "https://mainnet.neardata.xyz/v0/block/$H" \ + "${AUTH_HEADER[@]}" \ + | jq -r --arg contract "$TARGET_CONTRACT" ' + .shards[] + | select([.state_changes[]? | select(.change.account_id? == $contract)] | length > 0) + | .shard_id + ' | head -1)" + if [ -n "$SHARD" ]; then + FOUND_HEIGHT=$H; FOUND_SHARD=$SHARD + break + fi +done + +if [ -z "$FOUND_HEIGHT" ]; then + echo "no state mutation for $TARGET_CONTRACT in the last 16 finalized blocks" +else + curl -s "https://mainnet.neardata.xyz/v0/block/$FOUND_HEIGHT/shard/$FOUND_SHARD" \ + "${AUTH_HEADER[@]}" \ + | jq --arg contract "$TARGET_CONTRACT" --argjson height "$FOUND_HEIGHT" --argjson shard_id "$FOUND_SHARD" '{ + height: $height, + shard_id: $shard_id, + state_changes: [.state_changes[] | select(.change.account_id? == $contract) | {type, cause: (.cause | keys[0])}][0:3], + execution_outcomes: [.receipt_execution_outcomes[] | select(.execution_outcome.outcome.executor_id == $contract) | {receipt_id: .execution_outcome.id, status: (.execution_outcome.outcome.status | keys[0])}][0:3] + }' +fi +``` + +На mainnet `intents.near` живёт на shard 7, поэтому обход назад обычно попадает в цель за несколько блоков. Payload shard называет конкретные типы state-change (`account_update`, `data_update` и т. п.) и результаты receipt, которые их породили, — shard-локальное доказательство без догадок. Для менее активных контрактов расширьте диапазон `OFFSET`. + +## Когда расширить поверхность + +- Используйте [Transactions API](/tx), когда у вас уже есть `tx_hash` и нужна человекочитаемая история транзакции. +- Используйте [RPC Reference](/rpc), когда следующий вопрос касается точной протокольной семантики receipt или блока. +- Используйте [Block Headers](/neardata/block-headers), когда нужна только динамика head/finality, а не проверка contract-touch. diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/neardata/index.md b/i18n/ru/docusaurus-plugin-content-docs/current/neardata/index.md index ee4ac5b..af49e23 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/neardata/index.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/neardata/index.md @@ -1,6 +1,6 @@ --- title: "NEAR Data API" -description: "Кэшированные и архивные чтения по блокам для оптимистичных, финализированных и сценариев с перенаправлением." +description: "Недавние чтения по блокам и шардам для мониторинга активности контракта, подтверждения оптимистичных наблюдений и проверки изменений на уровне шарда." sidebar_position: 1 displayed_sidebar: nearDataApiSidebar slug: /neardata @@ -10,7 +10,7 @@ page_actions: # NEAR Data API -NEAR Data API — это поверхность для чтения данных почти в реальном времени, а также по семействам блоков. Используйте её, когда нужны свежие срезы блоков, вспомогательные маршруты с перенаправлением или недавние финализированные и оптимистичные чтения, но без позиционирования продукта как потокового сервиса. +NEAR Data API — это поверхность для недавних блоков и шардов. Используйте её, когда нужны свежие срезы блоков, мониторинг активности контракта, вспомогательные маршруты с перенаправлением или сравнение оптимистичных и финализированных чтений без превращения продукта в потоковый API. ## Базовые URL @@ -25,8 +25,9 @@ https://testnet.neardata.xyz ## Лучше всего подходит для - опроса недавних финализированных и оптимистичных блоков; -- вспомогательных маршрутов по блокам и сценариев с перенаправлением; -- лёгких проверок свежести данных и мониторинга. +- обнаружения того, появился ли живой контракт в недавнем блоке и изменил ли он состояние; +- сравнения оптимистичного сигнала с финализированным подтверждением; +- проверки одного недавнего шарда, когда уже известно, какой блок важен. ## Когда его не стоит использовать @@ -41,9 +42,14 @@ https://testnet.neardata.xyz ## С чего обычно начинают -- [Оптимистичный блок](/neardata/block-optimistic) — для самого свежего опроса блоков. -- [Финализированный блок по высоте](/neardata/block) и [Заголовки блока](/neardata/block-headers) — для запросов по финализированным блокам. -- [Перенаправление на последний финализированный блок](/neardata/last-block-final) и [Перенаправление на последний оптимистичный блок](/neardata/last-block-optimistic) — когда нужны вспомогательные маршруты с перенаправлением. +- [Перенаправление на последний финализированный блок](/neardata/last-block-final) и [Перенаправление на последний оптимистичный блок](/neardata/last-block-optimistic) — когда нужно быстро узнать самый новый недавний блок. +- [Финализированный блок по высоте](/neardata/block) — когда нужен один недавний гидратированный блок с уже приложенными данными по шардам. +- [Шард блока](/neardata/block-shard) — когда недавний блок уже показал нужный шард и его надо разобрать глубже. +- [Заголовки блока](/neardata/block-headers) — когда важнее движение головы цепочки и финальности, а не широкий блоковый документ. + +## Нужен сценарий? + +Используйте [примеры NEAR Data API](/neardata/examples) для практических примеров: обнаружения активности контракта, сравнения оптимистичных и финализированных наблюдений, а также проверки изменений на уровне шарда. ## Устранение неполадок diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/rpc/examples.md b/i18n/ru/docusaurus-plugin-content-docs/current/rpc/examples.md new file mode 100644 index 0000000..97b749f --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/rpc/examples.md @@ -0,0 +1,304 @@ +--- +sidebar_label: Examples +slug: /rpc/examples +title: "Примеры RPC" +description: "Практические примеры RPC: проверки состояния, инспекция блоков, чтение контрактов и отправка транзакций." +displayed_sidebar: rpcSidebar +page_actions: + - markdown +--- + +# Примеры RPC + +Начинайте с RPC-метода, который отвечает на вопрос. Используйте `tx`, чтобы отследить включение и финальность по хешу транзакции, и расширяйте поверхность только когда нужны дерево receipts, сырой state или трассировка на уровне shard. + +Все shell-примеры ниже работают на публичных RPC-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +## Состояние аккаунта + +### Показать баланс и storage аккаунта на finality + +`view_account` — канонический RPC-запрос для текущего состояния аккаунта. Один вызов возвращает свободный баланс, сумму, заблокированную в валидаторском стейке или lockup-контракте, использованное storage и блок, на котором было сделано чтение. `finality: "final"` гарантирует, что вы читаете стабильное состояние, а не optimistic-представление. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.mainnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_account",account_id:$account_id,finality:"final"} + }')" \ + | jq '.result | {amount, locked, storage_usage, block_height, block_hash}' +``` + +Для `root.near` это возвращает `amount` (yoctoNEAR в свободной части), `locked: "0"` (ничего в валидаторском стейке или lockup-контракте) и `storage_usage: 28677` — примерно 28.7 КБ on-chain-состояния. Пара `block_height`/`block_hash` фиксирует точку чтения; чтобы прочитать несколько аккаунтов *на одном и том же* блоке, переиспользуйте возвращённый `block_hash` как `block_id` в последующих запросах. + +## Включение транзакции и финальность + +### Отследить транзакцию от хеша до финальности + +Есть tx hash? Опрашивайте `tx` с минимальным порогом `wait_until`, который отвечает на ваш вопрос. + +```bash +TX_HASH=CVyG2xLJ6fuKCtULAxMnWTh2GL5ey2UUiTcgYT3M6Pow +SIGNER_ACCOUNT_ID=mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://archival-rpc.testnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" --arg signer_id "$SIGNER_ACCOUNT_ID" '{ + jsonrpc: "2.0", id: "fastnear", method: "tx", + params: {tx_hash: $tx_hash, sender_account_id: $signer_id, wait_until: "INCLUDED"} + }')" \ + | jq '{ + asked: "INCLUDED", + final_execution_status: .result.final_execution_status, + status_class: (.result.status | keys[0]), + receipts_outcome_count: (.result.receipts_outcome | length) + }' +``` + +Для зафиксированной исторической транзакции (1-yocto self-transfer от `mike.testnet`) ответ возвращается как `FINAL`, хотя мы спрашивали `INCLUDED`. Правило такое: **`wait_until` — это минимальный порог, а не целевой**. Узел возвращает тот этап, которого транзакция действительно достигла: для исторической всегда `FINAL`; для полётной выбирайте `INCLUDED`, когда достаточно включения и нужен самый ранний возврат, или `FINAL`, когда реальный вопрос звучит «завершилась ли?». + +Два перехода отсюда: + +- **Отправляете в реальном времени?** [`broadcast_tx_async`](/rpc/transaction/broadcast-tx-async) возвращает хеш сразу после того, как узел принял payload — отслеживайте отдельно через `tx`. [`send_tx`](/rpc/transaction/send-tx) одновременно отправляет и блокируется на выбранном `wait_until` в одном запросе. +- **Нужно дерево receipts, а не только outcome?** `tx` уже включает `receipts_outcome`; расширяйте поверхность до [`EXPERIMENTAL_tx_status`](/rpc/transaction/experimental-tx-status) только тогда, когда дополнительно нужны сырые записи receipts. + +## Инспекция блока на tip + +### Описать первый action первой транзакции на текущем tip + +Блок NEAR — это header поверх N shard chunks, а не плоский список транзакций. `block` возвращает headers chunks; сами транзакции лежат уровнем ниже, внутри `chunk`. Шортката `block → tx` нет — блок не несёт хешей транзакций, поэтому `tx` (которому нужен hash) в этой цепочке не участвует. Канонический проход — `status` → `block` → `chunk`, пропуская пустые chunks по дороге. Большинство chunks в tip-блоке пустые — их `tx_root` равен сентинелу `11111111111111111111111111111111`, поэтому селектору нужен фильтр. + +```bash +EMPTY_TX_ROOT=11111111111111111111111111111111 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +BLOCK_HASH="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data '{"jsonrpc":"2.0","id":"fastnear","method":"status","params":[]}' \ + | jq -r '.result.sync_info.latest_block_hash')" + +CHUNK_HASH="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg block_hash "$BLOCK_HASH" '{ + jsonrpc:"2.0",id:"fastnear",method:"block",params:{block_id:$block_hash} + }')" \ + | jq -r --arg empty "$EMPTY_TX_ROOT" ' + first(.result.chunks[] | select(.tx_root != $empty) | .chunk_hash) // empty')" + +if [ -z "$CHUNK_HASH" ]; then + echo "tip block had no transactions in any chunk — rerun on the next head" +else + curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg chunk_hash "$CHUNK_HASH" '{ + jsonrpc:"2.0",id:"fastnear",method:"chunk",params:{chunk_id:$chunk_hash} + }')" \ + | jq '{ + chunk_shard: .result.header.shard_id, + chunk_height: .result.header.height_included, + first_tx: { + hash: .result.transactions[0].hash, + signer_id: .result.transactions[0].signer_id, + receiver_id: .result.transactions[0].receiver_id + }, + first_action: ( + .result.transactions[0].actions[0] as $a + | if ($a | type) == "string" then {kind: $a} + elif $a.FunctionCall then {kind: "FunctionCall", method_name: $a.FunctionCall.method_name} + else {kind: ($a | keys[0])} end + ) + }' +fi +``` + +Живой запуск возвращает первый chunk текущего tip, первую транзакцию и первый action — часто это `FunctionCall` на контракте моста или tg-бота (mainnet активен). Tip-блок может быть валидным и при этом не содержать транзакций ни в одном chunk — поэтому ветка с пустым результатом остаётся; это честный ответ для тихого момента сети. + +## Механика аккаунтов и ключей + +### Определить function-call-ключи, которые стоит удалить + +Каждый кошелёк, шлюз и dapp-сессия, в которую вы заходите, обычно оставляет за собой function-call-ключ. Большинством из них вы больше никогда не воспользуетесь. `view_access_key_list` возвращает все ключи аккаунта; структура nonce показывает, какие из них устарели. + +Новые ключи стартуют с `block_height * 10^6`, и значение инкрементируется на единицу за каждую транзакцию, которую ключ подписывает, поэтому: + +- `nonce / 10^6` → блок, в котором ключ был добавлен +- `nonce % 10^6` → сколько раз ключ был использован + +Любой ключ с `tx_count: 0` был создан и ни разу не использовался — самый очевидный кандидат на очистку. Следующий по порядку — ключи, заскоупленные на контракт, с которым вы больше не работаете. Фильтр ниже сужает до `social.near`, но чтобы аудитировать другой контракт, меняется только строка `RECEIVER_ID`. + +```bash +ACCOUNT_ID=root.near +RECEIVER_ID=social.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.mainnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_access_key_list",account_id:$account_id,finality:"final"} + }')" \ + | jq --arg receiver "$RECEIVER_ID" ' + { + total_keys: (.result.keys | length), + fcks_for_receiver: [ + .result.keys[] + | select((.access_key.permission | type) == "object") + | select(.access_key.permission.FunctionCall.receiver_id == $receiver) + | { + public_key, + added_at_block: (.access_key.nonce / 1000000 | floor), + tx_count: (.access_key.nonce % 1000000), + method_names: (.access_key.permission.FunctionCall.method_names | if . == [] then "ANY" else . end), + allowance: (.access_key.permission.FunctionCall.allowance // "unlimited") + } + ] | sort_by(.tx_count) + }' +``` + +Для `root.near` это возвращает 235 ключей всего, включая 34 function-call-ключа на `social.near`; 21 из них были созданы и ни разу не использовались (`tx_count: 0`) и потому являются прямыми кандидатами на удаление. `method_names: "ANY"` означает, что ключ может вызвать любой метод на `social.near`; сужение до списка вида `["find_grants", "insert_grant", "delete_grant"]` означает, что ключ был заскоуплен на write-поверхность одного dapp. + +Чтобы удалить такой ключ, подпишите action `DeleteKey` **full-access**-ключом (function-call-ключ не может авторизовать `DeleteKey`) и отправьте через [`send_tx`](/rpc/transaction/send-tx). Повторный запуск того же запроса подтвердит, что ключа больше нет. + +## Чтение контрактов и сырой state + +### Прочитать storage контракта, не запуская его + +View-метод вроде `get_num` всё равно заставляет узел загрузить wasm-контракта и выполнить его. Если ключ storage уже известен, `view_state` возвращает сырые сериализованные байты напрямую — без исполнения и без зависимости от того, выставил ли контракт getter для этого поля вообще. + +Контракты на `near-sdk-rs` хранят верхнеуровневую `#[near_bindgen]`-структуру под ключом `STATE`. Передайте `STATE` как `prefix_base64` (`U1RBVEU=` — это base64 тех же четырёх ASCII-байт), и узел вернёт сериализованное значение. + +```bash +CONTRACT_ID=counter.near-examples.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +RAW_B64="$(curl -s "https://rpc.testnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg contract "$CONTRACT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_state",account_id:$contract,prefix_base64:"U1RBVEU=",finality:"final"} + }')" \ + | jq -r '.result.values[0].value')" + +DECODED_I8="$(python3 -c "import base64; print(int.from_bytes(base64.b64decode('$RAW_B64'),'little',signed=True))")" + +jq -n --arg raw "$RAW_B64" --argjson val "$DECODED_I8" '{raw_bytes_base64: $raw, decoded_i8: $val}' +``` + +Для живого counter это возвращает `"CQ=="` — один байт `0x09`, декодируется как signed i8 в `9`. Это то же число, которое вернул бы `get_num`, только прочитанное прямо из trie без запуска кода контракта. `signed=True` важен: отрицательный counter сериализовался бы как `"/w=="` (байт `0xff` → i8 `-1`, а не u8 `255`). + +Тянитесь к `view_state`, когда контракт не выставляет view-метод для нужных данных или когда нужна семья ключей, которую контракт не публикует. Для большинства чтений `call_function` всё равно требует меньше церемоний. Если вопрос становится историческим, а не текущим, расширяйте поверхность до [KV FastData API](/fastdata/kv). + +## NEAR Social и точные чтения BOS + +Оставайтесь на точных чтениях SocialDB и on-chain-проверках готовности — пока вопрос не станет историческим. + +### Может ли этот аккаунт прямо сейчас публиковать в NEAR Social? + +`social.near` знает две вещи, о которых UI кошелька может только догадываться: сколько storage осталось у каждого аккаунта и разрешена ли делегированному signer запись под этим аккаунтом. Два view-вызова сворачивают вопрос готовности к одному boolean. + +```bash +ACCOUNT_ID=root.near # account you're writing under +SIGNER_ACCOUNT_ID=root.near # account signing the transaction +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +STORAGE_ARGS_B64="$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id:$account_id}' | base64 | tr -d '\n')" + +STORAGE="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$STORAGE_ARGS_B64" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"get_account_storage",args_base64:$args,finality:"final"} + }')" \ + | jq '.result.result | implode | fromjson')" + +if [ "$SIGNER_ACCOUNT_ID" = "$ACCOUNT_ID" ]; then + PERMISSION=true +else + PERM_ARGS_B64="$(jq -nc --arg pred "$SIGNER_ACCOUNT_ID" --arg key "$ACCOUNT_ID" '{predecessor_id:$pred,key:$key}' | base64 | tr -d '\n')" + PERMISSION="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$PERM_ARGS_B64" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"is_write_permission_granted",args_base64:$args,finality:"final"} + }')" \ + | jq '.result.result | implode | fromjson')" +fi + +jq -n --argjson storage "$STORAGE" --argjson permission "$PERMISSION" \ + --arg account_id "$ACCOUNT_ID" --arg signer "$SIGNER_ACCOUNT_ID" '{ + account_id: $account_id, + signer_account_id: $signer, + storage: $storage, + permission_granted: $permission, + ready_to_publish: (($storage.available_bytes // 0) > 0 and $permission) + }' +``` + +Для `root.near`, подписывающего под собой, это возвращает `storage: {used_bytes: 136245, available_bytes: 42484}`, `permission_granted: true` (владельческая запись) и `ready_to_publish: true`. Если `storage` приходит как `null` или `available_bytes: 0`, аккаунту нужен `storage_deposit` на `social.near`, прежде чем новая запись сможет закрепиться. Если signer отличается от цели, ветка permission спрашивает `is_write_permission_granted({predecessor_id, key})` — тот же on-chain-ответ, который dapp видит, прежде чем писать от имени пользователя. Полную поверхность контракта см. в [SocialDB API](https://github.com/NearSocial/social-db#api). + +### Что `mob.near/widget/Profile` содержит прямо сейчас? + +SocialDB хранит BOS-виджеты как ключи `/widget/` на `social.near`. Один `keys` с типом возврата `BlockHeight` возвращает каталог плюс якоря последней записи по каждому виджету; один `get` возвращает точный исходник. + +```bash +ACCOUNT_ID=mob.near +WIDGET_NAME=Profile +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +KEYS_ARGS="$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + keys: [($account_id + "/widget/*")], + options: {return_type: "BlockHeight"} +}' | base64 | tr -d '\n')" + +curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$KEYS_ARGS" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"keys",args_base64:$args,finality:"final"} + }')" \ + | jq --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" ' + .result.result | implode | fromjson | .[$account_id].widget as $map + | { + total_widgets: ($map | length), + most_recently_written: ($map | to_entries | sort_by(-.value) | .[0:5] | map({widget: .key, last_write_block: .value})), + target_last_write_block: $map[$widget] + }' + +GET_ARGS="$(jq -nc --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" '{ + keys: [($account_id + "/widget/" + $widget)] +}' | base64 | tr -d '\n')" + +curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$GET_ARGS" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"get",args_base64:$args,finality:"final"} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" ' + .result.result | implode | fromjson | .[$account_id].widget[$widget] | split("\n")[0:20] | join("\n")' +``` + +Для `mob.near` каталог показывает 264 виджета; `Profile` последний раз записывался в блоке `86494825` — годами ранее, стабильно с тех пор — и исходник начинается с `const accountId = props.accountId ?? context.accountId;`. Тип возврата `BlockHeight` ничего не стоит дополнительно и превращает листинг ключей в дешёвую проверку актуальности. Сохраните блок последней записи, если позже захотите доказать, *какая транзакция* записала именно эту версию — передайте его в [Расширенный поиск записи SocialDB](/tx/socialdb-proofs). + +## Частые ошибки + +- Начинать в RPC, когда пользователю нужна сводка по активам или индексированная история. +- Забывать переключаться с обычного RPC на archival RPC для более старого state. +- Считать browser auth в UI документации продовым backend-паттерном. +- Оставаться в низкоуровневых вызовах статуса транзакции, когда вопрос уже стал forensic или историческим. + +## Связанные страницы + +- [RPC Reference](/rpc) +- [Auth & Access](/auth) +- [FastNear API](/api) +- [Transactions API](/tx) +- [Choosing the Right Surface](/agents/choosing-surfaces) +- [Agent Playbooks](/agents/playbooks) diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/rpc/index.md b/i18n/ru/docusaurus-plugin-content-docs/current/rpc/index.md index 148830a..34528f8 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/rpc/index.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/rpc/index.md @@ -43,6 +43,10 @@ https://archival-rpc.testnet.fastnear.com - [`send_tx`](/rpc/transaction/send-tx) — отправка транзакций; [`tx`](/rpc/transaction/tx-status) — статус исполнения. - [`validators`](/rpc/validators/validators-current) — валидаторы текущей эпохи. +## Нужен сценарий? + +Используйте [примеры RPC](/rpc/examples) для практических примеров: точных проверок состояния, анализа блоков, view-вызовов контрактов и отправки транзакций с подтверждением. + ## Используйте RPC, когда - нужны канонические формы запросов и ответов из протокола; diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/rpc/protocol/chunk-by-block-shard.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/rpc/protocol/chunk-by-block-shard.mdx index 4e1caa0..6534ab5 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/rpc/protocol/chunk-by-block-shard.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/rpc/protocol/chunk-by-block-shard.mdx @@ -12,5 +12,8 @@ import FastnearDirectOperation from '@site/src/components/FastnearDirectOperatio `chunk` — тип запроса. +Используйте этот маршрут, когда вы знаете координаты блока и шарда и хотите посмотреть, что именно этот шард исполнил в данном блоке. + +Это самый естественный RPC-маршрут для cross-shard debugging, потому что он отвечает на практический вопрос: «что исполнил шард X в блоке Y?» В ответе вы получаете заголовок чанка, а также транзакции и receipts в этой единице исполнения конкретного шарда. Если у вас уже есть точный хеш чанка, используйте [Чанк по хешу](/rpc/protocol/chunk-by-hash). Если нужна более полная shard-оболочка со state changes и produced receipts, переходите к [Block Shard](/neardata/block-shard). За готовым tracing-примером переходите в [RPC Examples](/rpc/examples). diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/rpc/protocol/chunk-by-hash.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/rpc/protocol/chunk-by-hash.mdx index 7f99188..5460067 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/rpc/protocol/chunk-by-hash.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/rpc/protocol/chunk-by-hash.mdx @@ -12,5 +12,8 @@ import FastnearDirectOperation from '@site/src/components/FastnearDirectOperatio `chunk` — тип запроса. +Используйте этот маршрут, когда другой инструмент уже выдал точный хеш чанка, а вам нужен канонический protocol chunk: заголовок, включённые транзакции и входящие receipts, которые этот шард исполнил в данном блоке. + +В NEAR подписанная транзакция может передать работу в receipts, а receipts потом продолжают исполняться в следующих чанках или на других шардах. Этот маршрут особенно уместен, когда хеш чанка уже известен из сводки по блоку, tracing-сценария или proof/debugging-потока. Если вы знаете координаты блока и шарда, используйте [Чанк по блоку и шарду](/rpc/protocol/chunk-by-block-shard). За готовым receipt-to-chunk walkthrough переходите в [RPC Examples](/rpc/examples). diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/snapshots/examples.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/snapshots/examples.mdx new file mode 100644 index 0000000..c740818 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/snapshots/examples.mdx @@ -0,0 +1,66 @@ +--- +sidebar_label: Examples +slug: /snapshots/examples +title: "Примеры snapshot" +description: "Практические примеры восстановления узла: optimized, standard и archival." +displayed_sidebar: snapshotsSidebars +page_actions: + - markdown +--- + +## Пути восстановления mainnet + +Выберите один класс — optimized `fast-rpc`, standard RPC или archival — и выполняйте только команды этого пути. Смешивание классов приводит к несогласованным данным узла. + +FastNear поддерживает эти скрипты ради скорости восстановления. Если в вашей среде требуется review изменений, скачайте скрипт и проверьте его перед запуском (вместо прямой передачи через pipe в `bash`). + +### Optimized mainnet `fast-rpc` + +```bash +DATA_PATH=~/.near/data + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone.sh \ + | DATA_PATH="$DATA_PATH" CHAIN_ID=mainnet RPC_TYPE=fast-rpc bash +``` + +### Standard mainnet RPC + +```bash +DATA_PATH=~/.near/data + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone.sh \ + | DATA_PATH="$DATA_PATH" CHAIN_ID=mainnet bash +``` + +### Archival mainnet + +Для archival нужны две загрузки из *одного и того же* среза снапшота. Зафиксируйте одно значение `LATEST` и переиспользуйте его и для hot-, и для cold-data — смешивание высот даёт внутренне несогласованный набор данных и удивляет nearcore на этапе настройки. + +```bash +HOT_DATA_PATH=~/.near/data +COLD_DATA_PATH=/mnt/hdds/cold-data + +LATEST="$(curl -s "https://snapshot.neardata.xyz/mainnet/archival/latest.txt")" +echo "Latest archival mainnet snapshot block: $LATEST" + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh \ + | DATA_TYPE=hot-data DATA_PATH="$HOT_DATA_PATH" CHAIN_ID=mainnet BLOCK="$LATEST" bash + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh \ + | DATA_TYPE=cold-data DATA_PATH="$COLD_DATA_PATH" CHAIN_ID=mainnet BLOCK="$LATEST" bash +``` + +## Частые ошибки + +- Использовать документацию по снапшотам, когда задача на самом деле про чтение данных цепочки. +- Выбирать archival-восстановление, когда достаточно standard или optimized RPC. +- Забывать про разделение hot/cold-хранилища для archival-данных. +- Переходить к командам до выбора сети и цели узла. + +## Связанные страницы + +- [Обзор snapshot](/snapshots) +- [Снапшоты mainnet](/snapshots/mainnet) +- [Снапшоты testnet](/snapshots/testnet) +- [RPC Reference](/rpc) +- [NEAR Data API](/neardata) diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/snapshots/index.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/snapshots/index.mdx index 4e33d25..c73d680 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/snapshots/index.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/snapshots/index.mdx @@ -63,6 +63,10 @@ sudo -v ; curl https://rclone.org/install.sh | sudo bash Требования к узлам смотрите в nearcore, а исходники скриптов загрузки, которые используются в этих руководствах, — в fastnear/static. +## Нужен сценарий? + +Используйте [примеры снапшотов](/snapshots/examples) для практических примеров: выбора между оптимизированным `fast-rpc`, стандартным восстановлением RPC и архивными путями с разделением горячих и холодных данных. + ## Выберите сеть
diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/transaction-flow/finality.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/transaction-flow/finality.mdx index a0be915..a994e47 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/transaction-flow/finality.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/transaction-flow/finality.mdx @@ -138,18 +138,24 @@ pub enum FinalExecutionStatus { ## Querying Outcomes +Эти RPC-чтения работают и на публичных FastNear RPC-хостах. Если `FASTNEAR_API_KEY` уже задан в окружении, сниппеты автоматически пробросят его как bearer-заголовок. + ### The `tx` RPC Method ```bash -curl -X POST https://rpc.mainnet.fastnear.com \ +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -X POST https://archival-rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": "1", "method": "tx", "params": { - "tx_hash": "6zgh2u9DqHHiXzdy9ouTP7oGky2T4nugqzqt9wJZwNFm", - "sender_account_id": "sender.near", + "tx_hash": "7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq", + "sender_account_id": "root.near", "wait_until": "FINAL" } }' diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/transaction-flow/reference.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/transaction-flow/reference.mdx index 6e8cc5b..e1d3caf 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/transaction-flow/reference.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/transaction-flow/reference.mdx @@ -174,11 +174,17 @@ You never "вызов" another контракта. You отправка them a l ### curl Examples +Эти RPC-чтения работают и на публичных FastNear RPC-хостах. Если `FASTNEAR_API_KEY` уже задан в окружении, сниппеты автоматически пробросят его как bearer-заголовок. + #### Submit Транзакция (Асинхронная) ```bash # Submit and get hash immediately +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + curl -X POST https://rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", @@ -194,7 +200,11 @@ curl -X POST https://rpc.mainnet.fastnear.com \ #### Submit Транзакция (Wait for Final) ```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + curl -X POST https://rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", @@ -207,15 +217,19 @@ curl -X POST https://rpc.mainnet.fastnear.com \ #### Check Транзакция Статус ```bash -curl -X POST https://rpc.mainnet.fastnear.com \ +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -X POST https://archival-rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": "1", "method": "tx", "params": { - "tx_hash": "6zgh2u9DqHHiXzdy9ouTP7oGky2T4nugqzqt9wJZwNFm", - "sender_account_id": "sender.testnet", + "tx_hash": "7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq", + "sender_account_id": "root.near", "wait_until": "FINAL" } }' @@ -224,7 +238,11 @@ curl -X POST https://rpc.mainnet.fastnear.com \ #### Просмотр доступ Key (for nonce) ```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + curl -X POST https://rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", @@ -233,8 +251,8 @@ curl -X POST https://rpc.mainnet.fastnear.com \ "params": { "request_type": "view_access_key", "finality": "final", - "account_id": "sender.testnet", - "public_key": "ed25519:DcA2MzgpJbrUATQLLceocVckhhAqrkingax4oJ9kZ847" + "account_id": "root.near", + "public_key": "ed25519:CByX7HPjgSGFi5G26zwgZGDFCFyBHvSv1fe7AFzmVe3" } }' @@ -245,7 +263,11 @@ curl -X POST https://rpc.mainnet.fastnear.com \ #### Get Recent Блок Hash ```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + curl -X POST https://rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/transaction-flow/runtime-execution.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/transaction-flow/runtime-execution.mdx index e09d955..f033013 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/transaction-flow/runtime-execution.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/transaction-flow/runtime-execution.mdx @@ -390,15 +390,19 @@ flowchart TD Clients can poll the `tx` RPC method with `wait_until: FINAL` to get all outcomes: ```bash -curl -X POST https://rpc.mainnet.fastnear.com \ +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -X POST https://archival-rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": "1", "method": "tx", "params": { - "tx_hash": "6zgh2u9DqHHiXzdy9ouTP7oGky2T4nugqzqt9wJZwNFm", - "sender_account_id": "sender.near", + "tx_hash": "7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq", + "sender_account_id": "root.near", "wait_until": "FINAL" } }' diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/transfers/examples.md b/i18n/ru/docusaurus-plugin-content-docs/current/transfers/examples.md new file mode 100644 index 0000000..b75ad53 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/transfers/examples.md @@ -0,0 +1,111 @@ +--- +sidebar_label: Examples +slug: /transfers/examples +title: "Примеры Transfers API" +description: "Практические примеры: фильтрация ленты переводов, пагинация и переход к истории транзакций." +displayed_sidebar: transfersApiSidebar +page_actions: + - markdown +--- + +## Примеры + +Эти shell-примеры работают и на публичных Transfers и Transactions endpoint-ах. Если `FASTNEAR_API_KEY` уже задан в окружении, сниппеты автоматически пробросят его как bearer-заголовок. + +### Какая у этого аккаунта свежая активность по переводам? + +`/v0/transfers` всего с `account_id` и `desc: true` возвращает самые свежие переводы, касающиеся этого аккаунта, по всем типам активов, в обоих направлениях сразу. В каждой строке уже есть `human_amount`, `asset_id` и `transaction_id`, так что этот поток заодно служит быстрым сканом активности до того, как вы достанете фильтры. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id: $account_id, desc: true, limit: 5}')" \ + | jq '{ + recent: [.transfers[] | { + block_height, + asset_id, + human_amount, + other_account_id, + transfer_type, + tx: .transaction_id + }] + }' +``` + +Для `root.near` последние строки смешивают активы `FtTransfer` и `MtTransfer`. `asset_id` использует URI по NEP-стандартам (`native:near`, `nep141:...`, `nep245:...`), так что одно поле уже подсказывает, к какому стандарту тянуться дальше. Положительный `human_amount` означает, что аккаунт получил; отрицательный — что отправил. `other_account_id: null` — норма для multi-token-форм, где контрагент сидит внутри границы контракта, а не как отдельный аккаунт верхнего уровня. + +### Отфильтровать и листать ленту переводов одного аккаунта + +`/v0/transfers` возвращает отфильтрованную ленту плюс `resume_token`, который вы переиспользуете *без изменения фильтров*, чтобы продолжать листать. В каждой строке уже есть `human_amount`, `usd_amount`, `transaction_id` и `receipt_id` — большинство audit-вопросов закрываются без второго запроса. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +FEED="$(curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + account_id: $account_id, + direction: "receiver", + asset_id: "native:near", + min_amount: "1000000000000000000000000", + desc: true, + limit: 10 + }')")" + +echo "$FEED" | jq '{ + resume_token, + transfers: [.transfers[] | {block_height, amount, human_amount, usd_amount, other_account_id, transaction_id, receipt_id}] +}' +``` + +Для зафиксированного аккаунта это возвращает недавние входящие native-NEAR переводы не меньше 1 NEAR — в примерных строках видны native-переводы с `escrow.ai.near` и уже посчитанным USD. Чтобы получить следующую страницу, отправьте то же тело с верхнеуровневым `resume_token: ""`; изменение любого другого фильтра делает токен недействительным. + +Когда одной строке нужна точка исполнения, возьмите её `receipt_id` и сразу обратитесь к `/v0/receipt`: + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +FEED="$(curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + account_id: $account_id, + direction: "receiver", + asset_id: "native:near", + min_amount: "1000000000000000000000000", + desc: true, + limit: 10 + }')")" +RECEIPT_ID="$(echo "$FEED" | jq -r '.transfers[0].receipt_id')" + +curl -s "https://tx.main.fastnear.com/v0/receipt" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg receipt_id "$RECEIPT_ID" '{receipt_id: $receipt_id}')" \ + | jq '.receipt | {receipt_id, transaction_hash, receiver_id, predecessor_id, tx_block_height, is_success}' +``` + +Это тот же переход, что описан в [Превратить один receipt ID в читаемую историю транзакции](/tx/examples#receipt-id-to-readable-story) — один запрос возвращает и квитанцию, и её родительскую транзакцию целиком. + +## Частые ошибки + +- Использовать Transfers API, когда пользователю на самом деле нужны балансы, активы или сводки аккаунта. +- Считать историю переводов полной историей исполнения. +- Переиспользовать `resume_token` с другими фильтрами. + +## Связанные страницы + +- [Transfers API](/transfers) +- [Transactions API](/tx) +- [FastNear API](/api) +- [Choosing the Right Surface](/agents/choosing-surfaces) +- [Agent Playbooks](/agents/playbooks) diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/transfers/index.md b/i18n/ru/docusaurus-plugin-content-docs/current/transfers/index.md index 538b46c..22d7c72 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/transfers/index.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/transfers/index.md @@ -66,6 +66,10 @@ https://transfers.main.fastnear.com - [Запрос переводов](/transfers/query) — лента по аккаунту с фильтрами по направлению, активу, сумме и времени +## Нужен сценарий? + +Используйте [Transfers API Examples](/transfers/examples) для практических примеров: узкие поиски переводов, пагинация через `resume_token` и переход к более широкому расследованию транзакций. + ## Устранение неполадок ### Нужны полные метаданные транзакции diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/tx/berry-club.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/tx/berry-club.mdx new file mode 100644 index 0000000..e849337 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/tx/berry-club.mdx @@ -0,0 +1,152 @@ +--- +sidebar_label: Berry Club +slug: /tx/examples/berry-club +title: "Berry Club: как читать живую доску и разбирать одну эпоху" +description: "Прочитайте живую доску Berry Club через RPC get_lines, а затем используйте Transactions API, чтобы восстановить одну более раннюю эпоху." +displayed_sidebar: transactionsApiSidebar +page_actions: + - markdown +keywords: + - Berry Club + - FastNear + - Transactions API + - RPC + - get_lines + - draw + - pixel board +--- + +import Link from '@site/src/components/LocalizedLink'; +import BerryClubLiveBoard from '@site/src/components/BerryClubLiveBoard'; + +{/* FASTNEAR_AI_DISCOVERY: Этот walkthrough показывает краткий и полезный путь для Berry Club: сначала прочитайте живую доску через RPC get_lines, а Transactions API используйте только тогда, когда нужно восстановить одну более раннюю эпоху по draw-вызовам. */} + +# Berry Club: как читать живую доску и разбирать одну эпоху + +Используйте этот walkthrough, когда живую доску читать легко, но нужен один понятный путь к исторической реконструкции. + +Начните с живой доски. Если этого уже достаточно для ответа, на этом можно остановиться. + +Переходите к Transactions API только тогда, когда вопрос становится историческим: «как Berry Club выглядел в одной более ранней эпохе и какие `draw`-вызовы сделали доску именно такой?» + +Эти shell-примеры работают и с публичными RPC и Transactions endpoint-ами. Если `FASTNEAR_API_KEY` уже задан в окружении, FastNear-вызовы автоматически пробросят его как bearer-заголовок. + + + +## 1. Прочитайте живую доску + +Это самый короткий полезный запрос: + +```bash +ARGS_BASE64="$(jq -nc '{lines: [range(0;50)]}' | base64 | tr -d '\n')" +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "{ + \"jsonrpc\": \"2.0\", + \"id\": \"berry-live-board\", + \"method\": \"query\", + \"params\": { + \"request_type\": \"call_function\", + \"finality\": \"final\", + \"account_id\": \"berryclub.ek.near\", + \"method_name\": \"get_lines\", + \"args_base64\": \"$ARGS_BASE64\" + } + }" | jq '.result | {block_height, line_count: (.result | implode | fromjson | length)}' +``` + +Этот запрос отдаёт текущую доску 50x50 прямо из контракта. Дальше нужно только декодировать каждую base64-строку в 50 цветов пикселей. + +## 2. Восстановите одну более раннюю эпоху + +Когда нужна история, держите путь коротким: + +1. ограничьте одну эпоху +2. получите кандидатные `draw`-транзакции для `berryclub.ek.near` +3. раскройте эти хеши +4. проиграйте массивы `pixels` от старых к новым + +В этом примере используется узкое окно вокруг блока `97601515`: + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://tx.main.fastnear.com/v0/account \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{ + "account_id": "berryclub.ek.near", + "is_function_call": true, + "is_receiver": true, + "is_real_receiver": true, + "from_tx_block_height": 97576515, + "to_tx_block_height": 97601516, + "desc": false, + "limit": 200 + }' | jq '.account_txs | map({transaction_hash, tx_block_height}) | .[-5:]' +``` + +Если окно ещё нужно подобрать, сначала можно использовать `/v0/blocks`. Это не часть основного Berry Club-сценария. + +Раскройте кандидатные хеши и оставьте только верхнеуровневые вызовы `draw`: + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://tx.main.fastnear.com/v0/transactions \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{ + "tx_hashes": [ + "Hq5qwsuiM2emJrqczWM9awCa7o6sTBYqYpcifUX2SUhQ", + "8tBip5M2TrozhSyepAA3tYXpyKooi5t7b9c64wXjFvfL" + ] + }' | jq '.transactions[] + | select(.transaction.receiver_id == "berryclub.ek.near") + | .transaction.actions[]?.FunctionCall + | select(.method_name == "draw") + | {method_name, args: (.args | @base64d | fromjson)}' +``` + +Затем проиграйте массивы `pixels` от старых к новым: + +```javascript +const board = Array.from({ length: 50 }, () => Array(50).fill(0)); + +for (const drawTx of drawTransactionsOldestFirst) { + for (const pixel of drawTx.args.pixels) { + if (pixel.x < 0 || pixel.x >= 50 || pixel.y < 0 || pixel.y >= 50) { + continue; + } + + board[pixel.y][pixel.x] = pixel.color; + } +} +``` + +В этом и состоит исторический паттерн. У Berry Club нет готового эндпоинта «доска на блоке N», поэтому старые эпохи восстанавливаются проигрыванием `draw`-записей. + +## Связанные руководства + +- RPC: call_function +- Transactions API: история аккаунта +- Transactions API: транзакции по хешу diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/tx/examples.md b/i18n/ru/docusaurus-plugin-content-docs/current/tx/examples.md new file mode 100644 index 0000000..30a6111 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/tx/examples.md @@ -0,0 +1,254 @@ +--- +sidebar_label: Examples +slug: /tx/examples +title: "Примеры Transactions" +description: "Практические расследования транзакций: хеши, receipts, async-сбои и callback." +displayed_sidebar: transactionsApiSidebar +page_actions: + - markdown +--- + +## Начните здесь + +Все shell-примеры ниже работают на публичных Transactions API-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### У меня один хеш транзакции. Что произошло? + +Вставьте хеш в `POST /v0/transactions` — один ответ обычно содержит всю историю. + +```bash +TX_HASH=7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq '{ + hash: .transactions[0].transaction.hash, + signer_id: .transactions[0].transaction.signer_id, + receiver_id: .transactions[0].transaction.receiver_id, + included_block_height: .transactions[0].execution_outcome.block_height, + actions: (.transactions[0].transaction.actions | map(if type == "string" then . else keys[0] end)), + first_receipt_id: .transactions[0].execution_outcome.outcome.status.SuccessReceiptId, + receipt_count: (.transactions[0].receipts | length) + }' +``` + +Для зафиксированного хеша `root.near` отправил один `Transfer` на `escrow.ai.near` в блоке `188976785`, с передачей в receipt `B8QzHQZ6VnUVy8zaVXCEkWuSs7MPb34yoHYixZV3Zdj1`. Если `receipt_count > 1` или следующий вопрос касается поведения на уровне receipt, переходите к [Какой receipt испустил этот лог или событие?](#какой-receipt-испустил-этот-лог-или-событие) или [`POST /v0/receipt`](/tx/receipt). + +### Какой receipt испустил этот лог или событие? + +Выведите список всех receipt транзакции с логами и флагом, содержат ли их логи ваш фрагмент. Совпадение доказывается, а не угадывается: у зафиксированной транзакции один receipt логирует `Transfer`, другой — `Refund`, и только сторона `Refund` переключается в `true`. + +```bash +TX_HASH=2KhhB1uDScGCFQfVchep7DiZTGTxMcgfUYHNzwf5e6uL +LOG_FRAGMENT=Refund +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg fragment "$LOG_FRAGMENT" ' + [ + .transactions[0].receipts[] + | select((.execution_outcome.outcome.logs | length) > 0) + | { + receipt_id: .receipt.receipt_id, + receiver_id: .receipt.receiver_id, + method_name: (.receipt.receipt.Action.actions[0] + | if type == "string" then . else (.FunctionCall.method_name // keys[0]) end), + matches_fragment: any(.execution_outcome.outcome.logs[]?; contains($fragment)), + logs: .execution_outcome.outcome.logs + } + ]' +``` + +Фрагмент `Refund` атрибутируется receipt `9sLHQpaGz3NnMNMn8zGrDUSyktR1q6ts2otr9mHkfD1w` на `wrap.near`, метод `ft_resolve_transfer`. Логи receipt живут на receipts, а не на транзакции, поэтому одного прохода достаточно — более глубокая async-трассировка не нужна. + +### Превратить один receipt ID в читаемую историю транзакции {#receipt-id-to-readable-story} + +`POST /v0/receipt` возвращает запись receipt **и** его полную родительскую транзакцию в одном ответе, поэтому единственного запроса хватает на всю историю — дополнительный `/v0/transactions` не нужен. + +```bash +RECEIPT_ID=B8QzHQZ6VnUVy8zaVXCEkWuSs7MPb34yoHYixZV3Zdj1 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/receipt" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg receipt_id "$RECEIPT_ID" '{receipt_id: $receipt_id}')" \ + | jq '{ + receipt: { + receipt_id: .receipt.receipt_id, + type: .receipt.receipt_type, + is_success: .receipt.is_success, + receipt_block: .receipt.block_height, + tx_block: .receipt.tx_block_height, + predecessor_id: .receipt.predecessor_id, + receiver_id: .receipt.receiver_id, + transaction_hash: .receipt.transaction_hash + }, + parent_transaction: { + signer_id: .transaction.transaction.signer_id, + receiver_id: .transaction.transaction.receiver_id, + action_types: (.transaction.transaction.actions | map(if type == "string" then . else keys[0] end)) + } + }' +``` + +Для зафиксированного receipt это возвращает `Action`-receipt от `root.near` к `escrow.ai.near`, который успешно выполнился в блоке `188976786`, через один блок после попадания родительской транзакции `7ZKnhzt2…`, — один `Transfer` (3.5 NEAR, в сыром `.transaction.transaction.actions` видимо как `3500000000000000000000000` yocto). Если интересным якорем становится родительская транзакция, хеш у вас уже есть — переиспользуйте его в [У меня один хеш транзакции. Что произошло?](#у-меня-один-хеш-транзакции-что-произошло). + +## Сбои и async + +### Доказать, что один провалившийся action откатил весь batch + +Один batch отправил `CreateAccount → Transfer → AddKey → FunctionCall`, и финальный вызов попал в отсутствующий метод. Индексированная запись транзакции уже несёт упорядоченный batch *и* точный сбой на уровне receipt, поэтому одного запроса хватает, чтобы ответить «что пытались и что сломалось»; проверка через `view_account` затем доказывает, что предыдущие actions откатились. + +```bash +TX_HASH=CrhH3xLzbNwNMGgZkgptXorwh8YmqxRGuA6Mc11MkU6M +NEW_ACCOUNT_ID=rollback-mo4vmkig.temp.mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.test.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq '{ + action_types: (.transactions[0].transaction.actions | map(if type == "string" then . else keys[0] end)), + final_method: .transactions[0].transaction.actions[3].FunctionCall.method_name, + tx_handoff: .transactions[0].execution_outcome.outcome.status, + receipt_failure: ( + first( + .transactions[0].receipts[] + | select(.execution_outcome.outcome.status.Failure != null) + | .execution_outcome.outcome.status.Failure.ActionError + ) + ) + }' +``` + +Статус на уровне транзакции — `SuccessReceiptId`: транзакция успешно передала свои batched actions в receipt. Сбой лежит слоем ниже на этом receipt: `index: 3` (именно `FunctionCall`), вид `CodeDoesNotExist` на `rollback-mo4vmkig.temp.mike.testnet`. `SuccessReceiptId` в tx-outcome означает «handoff прошёл», а не «всё завершилось» — реальная ловушка, если смотреть только на статус уровня транзакции. + +Теперь докажите откат предыдущих actions: спросите аккаунт, который batch *пытался* создать: + +```bash +NEW_ACCOUNT_ID=rollback-mo4vmkig.temp.mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.testnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$NEW_ACCOUNT_ID" '{ + jsonrpc: "2.0", id: "fastnear", method: "query", + params: {request_type: "view_account", account_id: $account_id, finality: "final"} + }')" \ + | jq '{error: .error.cause.name, requested_account_id: .error.cause.info.requested_account_id}' +``` + +`UNKNOWN_ACCOUNT` — это и есть доказательство. Если бы `CreateAccount` закрепился, `view_account` вернул бы результат; раз нет — предыдущие `Transfer` и `AddKey` из того же batched-receipt тоже не закрепились. + +### Когда транзакция выглядит успешной — что на самом деле произошло? + +Внешний `execution_outcome.outcome.status` рапортует `SuccessReceiptId`, как только сработал handoff первого receipt, — и ничего не говорит о том, успешны ли дочерние receipts и отработал ли callback на исходном контракте. Один pipeline над `/v0/transactions` отвечает сразу на все три вопроса. + +```bash +TX_HASH=2KhhB1uDScGCFQfVchep7DiZTGTxMcgfUYHNzwf5e6uL +ORIGIN_CONTRACT_ID=wrap.near +CALLBACK_METHOD=ft_resolve_transfer +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg origin "$ORIGIN_CONTRACT_ID" --arg callback "$CALLBACK_METHOD" '{ + outer: { + method: .transactions[0].transaction.actions[0].FunctionCall.method_name, + tx_handoff: (.transactions[0].execution_outcome.outcome.status | keys[0]) + }, + callback: { + expected_on: $origin, + method: $callback, + ran: any( + .transactions[0].receipts[]; + .receipt.receiver_id == $origin + and (.receipt.receipt.Action.actions[0].FunctionCall.method_name // "") == $callback + ) + }, + descendant_failures: [ + .transactions[0].receipts[] + | select(.execution_outcome.outcome.status.Failure != null) + | { + receiver_id: .receipt.receiver_id, + method: (.receipt.receipt.Action.actions[0].FunctionCall.method_name // "system"), + cause: .execution_outcome.outcome.status.Failure + } + ] + }' +``` + +Для зафиксированной транзакции `outer.method` — `ft_transfer_call`, а `outer.tx_handoff` — `SuccessReceiptId`: транзакция чисто запустила свой первый receipt, и если смотреть только сюда, можно назвать это победой. `descendant_failures` рассказывают вторую историю: `ft_on_transfer` на `v2.ref-finance.near` упал с `E51: contract paused` — DEX был на паузе во время этого свопа и не мог принять wrapped NEAR. `callback.ran: true` — третью: callback `ft_resolve_transfer` на `wrap.near` всё равно отработал. Сбой ниже по цепочке никогда не мешает callback исходного контракта — именно так NEP-141 возвращает отправителю средства, когда получатель их отклонил. + +Успех receipt не транзитивен. Протокол может чисто отдать handoff и при этом увидеть, как отцеплённая работа провалится позже; callback исходного контракта отработает в любом случае. Прочитайте эти три поля вместе — и async-история становится читаемой без ручного обхода цепочки receipts. Чтобы вытянуть сам лог `Refund`, переходите к [Какой receipt испустил этот лог или событие?](#какой-receipt-испустил-этот-лог-или-событие). + +### Сопоставить запрос OutLayer с его TEE-разрешением + +[OutLayer](https://outlayer.fastnear.com) разделяет один логический вызов на две транзакции: пользователь подписывает `request_execution` на `outlayer.near`, worker в Intel TDX запускает нужный WASM off-chain, затем `worker.outlayer.near` присылает результат через `submit_execution_output_and_resolve`. Обе половины несут один и тот же `request_id` — передайте оба tx-хеша в один запрос `/v0/transactions` и извлеките это поле с каждой стороны, чтобы подтвердить пару. + +```bash +REQUEST_TX=BZDQAxEdpQ9wUGXmXTa2APwFLDTTqTy5ucrBPsfgZeyz +WORKER_TX=3NYD4Mkn5cwkuVkGP9PPoiJ9PB5Vr7v6r8CwSswtHVA3 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg a "$REQUEST_TX" --arg b "$WORKER_TX" '{tx_hashes: [$a, $b]}')" \ + | jq '[ + .transactions[] + | { + role: (if .transaction.actions[0].FunctionCall.method_name == "request_execution" + then "request" else "worker" end), + hash: .transaction.hash, + signer: .transaction.signer_id, + method: .transaction.actions[0].FunctionCall.method_name, + block: .execution_outcome.block_height, + request_id: ( + if .transaction.actions[0].FunctionCall.method_name == "request_execution" + then (.receipts[0].execution_outcome.outcome.logs[] | select(startswith("EVENT_JSON")) + | sub("EVENT_JSON:"; "") | fromjson | .data[0].request_data | fromjson | .request_id) + else (.receipts[0].receipt.receipt.Action.actions[0].FunctionCall.args + | @base64d | fromjson | .request_id) + end + ) + } + ]' +``` + +Обе строки несут `request_id: 1868`, подтверждая пару. Половина-запрос, подписанная `retrorn.near` в блоке `194832281`, лежит в логе `EVENT_JSON:` её receipt (это yield/resume-паттерн NEAR — on-chain-обещание приостанавливается, пока TDX-worker выполняется). Половина-worker приходит через 11 блоков с `submit_execution_output_and_resolve`, подписанной `worker.outlayer.near`, и её `request_id` достаётся прямо из base64-обёрнутых `FunctionCall.args`. Те же два payload несут и более богатый отпечаток — `sender_id`, `project_id`, `code_hash`, `resources_used.instructions`, `resources_used.time_ms`, размер зашифрованного результата в байтах — если нужно проверить, что именно исполнилось; этот минимальный pipeline лишь подтверждает, что половины принадлежат друг другу. `/v0/transactions` отдаёт исторические пары бессрочно, поэтому archival RPC для самой трассировки не нужен даже через недели. + +## Частые ошибки + +- Пытаться отправить транзакцию через history-API вместо raw RPC. +- Использовать Transactions API, когда пользователю нужны только текущие балансы или активы. +- Спускаться в raw RPC до того, как индексированная история ответила на читаемый вопрос «что произошло?». + +## Связанные страницы + +- [Transactions API](/tx) +- [RPC Reference](/rpc) +- [FastNear API](/api) +- [NEAR Data API](/neardata) +- [Berry Club: живая доска и один путь исторической реконструкции](/tx/examples/berry-club) +- [Расширенный поиск записи SocialDB](/tx/socialdb-proofs) +- [Choosing the Right Surface](/agents/choosing-surfaces) +- [Agent Playbooks](/agents/playbooks) diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/tx/index.md b/i18n/ru/docusaurus-plugin-content-docs/current/tx/index.md index 277799b..da4b19a 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/tx/index.md +++ b/i18n/ru/docusaurus-plugin-content-docs/current/tx/index.md @@ -48,6 +48,10 @@ https://tx.test.fastnear.com - [Поиск квитанции](/tx/receipt) — для расследования цепочки исполнения. - [Диапазон блоков](/tx/blocks) — когда нужен ограниченный по диапазону просмотр истории. +## Нужен сценарий? + +Используйте [примеры API транзакций](/tx/examples) для практических примеров: поиска транзакций, расследования квитанций, истории аккаунта и анализа диапазонов блоков. + ## Устранение неполадок ### Я ожидал, что здесь можно отправлять транзакции diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/tx/socialdb-proofs.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/tx/socialdb-proofs.mdx new file mode 100644 index 0000000..1fa6741 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/tx/socialdb-proofs.mdx @@ -0,0 +1,162 @@ +--- +slug: /tx/socialdb-proofs +title: Расширенный поиск записи SocialDB +description: Один короткий расширенный сценарий, который начинается с читаемого значения SocialDB и восстанавливает транзакцию записи за ним. +displayed_sidebar: transactionsApiSidebar +page_actions: + - markdown +--- + +# Расширенный поиск записи SocialDB + +Используйте эту страницу только тогда, когда отправная точка — уже читаемое значение SocialDB из `api.near.social`, а следующий вопрос относится к историческому поиску записи. + +Эти shell-шаги работают и с публичными endpoint-ами SocialDB и FastNear. Если `FASTNEAR_API_KEY` уже задан в окружении, FastNear-вызовы автоматически пробросят его как bearer-заголовок. + +Для FastNear-first-задач сначала откройте [Transactions Examples](/tx/examples). Сюда переходите только тогда, когда вопрос звучит как «какая запись сделала это читаемое значение SocialDB истинным?». + +## Канонический пример: доказать, что `root.near` установил `profile.name` в `Illia` + +Используйте этот сценарий, когда читаемый факт уже звучит как «текущее `profile.name` равно `Illia`», а остаётся вопрос, какая запись сделала это поле истинным. + +Это единственный нюанс SocialDB, который стоит запомнить: для исторического доказательства правильным мостом обычно служит `:block` на уровне поля, а не `:block` родительского объекта. + +Для этого живого якоря: + +- текущее `profile.name`: `Illia` +- блок записи SocialDB на уровне поля: `75590392` +- receipt ID: `GYvnvBxWA46UGa3aGEkqUBeT7hxhVXk2iZScJFZWU8Se` +- хеш исходной транзакции: `7HtFWv51k5Bispmh1WYPbAVkxr2X4AL6n98DhcQwVw7w` +- внешний блок транзакции: `75590391` + +### Shell-сценарий + +1. Прочитайте поле из NEAR Social и сохраните блок записи на уровне поля. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name + +PROFILE="$(curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')")" + +echo "$PROFILE" | jq --arg account_id "$ACCOUNT_ID" '{ + current_name: .[$account_id].profile.name[""], + field_block_height: .[$account_id].profile.name[":block"], + parent_profile_block_height: .[$account_id].profile[":block"] +}' + +PROFILE_BLOCK_HEIGHT="$(echo "$PROFILE" | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]')" +``` + +2. Переиспользуйте этот блок уровня поля в FastNear block receipts и восстановите receipt вместе с tx hash. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +PROFILE_BLOCK_HEIGHT="$( + curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]' +)" +BLOCK_RECEIPTS="$(curl -s "https://tx.main.fastnear.com/v0/block" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --argjson block_id "$PROFILE_BLOCK_HEIGHT" '{ + block_id: $block_id, + with_transactions: false, + with_receipts: true + }')")" + +echo "$BLOCK_RECEIPTS" | jq --arg account_id "$ACCOUNT_ID" '{ + profile_receipt: ( + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | {receipt_id, transaction_hash, block_height, tx_block_height} + ) + ) +}' + +PROFILE_TX_HASH="$(echo "$BLOCK_RECEIPTS" | jq -r --arg account_id "$ACCOUNT_ID" ' + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | .transaction_hash + )')" +``` + +3. Переиспользуйте этот tx hash в `POST /v0/transactions` и декодируйте payload записи SocialDB. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +PROFILE_BLOCK_HEIGHT="$( + curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]' +)" +PROFILE_TX_HASH="$( + curl -s "https://tx.main.fastnear.com/v0/block" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --argjson block_id "$PROFILE_BLOCK_HEIGHT" '{ + block_id: $block_id, + with_transactions: false, + with_receipts: true + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" ' + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | .transaction_hash + )' +)" +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$PROFILE_TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg account_id "$ACCOUNT_ID" '{ + transaction: { + hash: .transactions[0].transaction.hash, + signer_id: .transactions[0].transaction.signer_id, + receiver_id: .transactions[0].transaction.receiver_id, + included_block_height: .transactions[0].execution_outcome.block_height + }, + write_proof: ( + .transactions[0].receipts[0].receipt.receipt.Action.actions[0].FunctionCall + | (.args | @base64d | fromjson | .data[$account_id].profile) as $profile + | { + method_name, + profile_name: $profile.name, + image_fields: (($profile.image // {}) | keys), + linktree_keys: (($profile.linktree // {}) | keys) + } + ) + }' +``` + +Это и есть весь паттерн lookup: читаемое значение, блок уровня поля, мост через receipt и payload транзакции. + +Тот же мост работает и для других читаемых значений SocialDB: + +- вариант для связи подписки: `root.near -> mob.near`, блок `79152039`, tx `DvNoqtDrruhmcq7mPpxdFacph2ZCqSzMFF5ZqMRFG78q` +- вариант для исходника виджета: `root.near/widget/Profile`, блок `76029540`, tx `ELS3DrE4Upoc91ZnBh4thVugxCUBAbaLFB4nyKsoyRNP` + +Ключевая идея не меняется: начните с читаемого значения и его write-block, восстановите receipt `*.near -> social.near` из блока, а затем декодируйте payload `social.near set` из исходной транзакции. diff --git a/i18n/ru/translation-policy.yml b/i18n/ru/translation-policy.yml index 3740d10..66f68e8 100644 --- a/i18n/ru/translation-policy.yml +++ b/i18n/ru/translation-policy.yml @@ -114,10 +114,16 @@ waves: docs: - redocly-config.md - internationalization.md + - api/examples.md - api/reference.md + - fastdata/kv/examples.md + - neardata/examples.md + - snapshots/examples.mdx - transfers/index.md + - transfers/examples.md - snapshots/mainnet.mdx - snapshots/testnet.mdx + - rpc/examples.md - rpc/account/view-access-key-list.mdx - rpc/account/view-access-key.mdx - rpc/account/view-account.mdx @@ -147,6 +153,7 @@ waves: - rpc/transaction/send-tx.mdx - rpc/transaction/tx-status.mdx - rpc/validators/experimental-validators-ordered.mdx + - tx/examples.md pageModels: - rpc-view-global-contract-code-by-account-id - rpc-view-global-contract-code diff --git a/scripts/generate-ai-surfaces.js b/scripts/generate-ai-surfaces.js index 27e4464..38478e6 100644 --- a/scripts/generate-ai-surfaces.js +++ b/scripts/generate-ai-surfaces.js @@ -3,6 +3,7 @@ const fs = require("fs"); const path = require("path"); const { isSecretQueryParam } = require("../src/utils/fastnearOperationUrlState"); +const AI_MARKDOWN_FOOTER_COPY = require("../src/data/fastnearAiMarkdownFooter.json"); const { DEFAULT_LOCALE, @@ -106,6 +107,10 @@ const AUTHORED_MARKDOWN_LABELS = { en: { aiAndAgents: "AI & Agents", bestFor: "Best for:", + berryClubLiveBoardNote: + "Live board card: fetches `berryclub.ek.near` `get_lines` from mainnet RPC and renders the current 50x50 grid in the docs UI.", + berryClubGalleryNote: + "Rendered snapshot gallery: launch, mid, and recent checkpoints from checked-in `src/data/berryClubSnapshots.json`.", guidesArchiveTitle: "FastNear Builder Docs Full Documentation Archive", guidesArchiveIntro: "AI-readable Markdown mirrors for authored docs plus canonical `/rpcs/**` and `/apis/**` routes.", @@ -137,6 +142,10 @@ const AUTHORED_MARKDOWN_LABELS = { ru: { aiAndAgents: "AI и агенты", bestFor: "Лучше всего подходит для:", + berryClubLiveBoardNote: + "Карточка живой доски: запрашивает `berryclub.ek.near` `get_lines` через mainnet RPC и рендерит текущую сетку 50x50 в интерфейсе документации.", + berryClubGalleryNote: + "Галерея снимков: контрольные точки launch, mid и recent из сохранённого `src/data/berryClubSnapshots.json`.", guidesArchiveTitle: "Полный архив документации FastNear Builder Docs", guidesArchiveIntro: "AI-читабельные Markdown-копии авторских гайдов и канонических маршрутов `/rpcs/**` и `/apis/**`.", @@ -404,6 +413,32 @@ function normalizeMarkdown(markdown) { return markdown.replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n").trim(); } +function getFastnearAiFooterCopy(locale = DEFAULT_LOCALE) { + return ( + AI_MARKDOWN_FOOTER_COPY[locale] || + AI_MARKDOWN_FOOTER_COPY[DEFAULT_LOCALE] || + AI_MARKDOWN_FOOTER_COPY.en + ); +} + +function buildFastnearAiFooter(locale = DEFAULT_LOCALE) { + const footerCopy = getFastnearAiFooterCopy(locale); + const sections = [ + `## ${footerCopy.title}`, + "", + ...footerCopy.bullets.map((bullet) => `- ${bullet}`), + ]; + + return `${normalizeMarkdown(sections.join("\n"))}\n`; +} + +function appendFastnearAiFooter(markdown, locale = DEFAULT_LOCALE) { + const normalizedBody = normalizeMarkdown(markdown || ""); + const footer = buildFastnearAiFooter(locale).trim(); + + return `${normalizeMarkdown([normalizedBody, "---", "", footer].filter(Boolean).join("\n"))}\n`; +} + function rewriteRootRelativeMarkdownLinks(markdown, locale = DEFAULT_LOCALE) { return markdown.replace( /(!?\[[^\]]*]\()((?:<)?\/[^)\s>]+(?:>)?)(\))/g, @@ -654,6 +689,18 @@ function transformSimpleJsx(markdown, locale = DEFAULT_LOCALE) { return transformed; } +function transformSpecialComponents(markdown, locale = DEFAULT_LOCALE) { + const labels = getAuthoredMarkdownLabels(locale); + + return markdown.replace( + //g, + `\n\n${labels.berryClubLiveBoardNote}\n\n` + ).replace( + //g, + `\n\n${labels.berryClubGalleryNote}\n\n` + ); +} + function removeImports(markdown) { return markdown.replace(/^import\s+.+?;?\n/gm, ""); } @@ -679,6 +726,7 @@ function renderAuthoredMarkdown(content, route, filePath, locale = DEFAULT_LOCAL let markdown = removeImports(content); markdown = transformCardGrid(markdown, locale); markdown = transformInlineLinks(markdown, locale); + markdown = transformSpecialComponents(markdown, locale); markdown = transformSimpleJsx(markdown, locale); markdown = rewriteRootRelativeMarkdownLinks(markdown, locale); assertNoUnsupportedJsx(markdown, filePath); @@ -1384,12 +1432,15 @@ function createAuthoredDocEntries(locale = DEFAULT_LOCALE) { return null; } + const markdownBody = buildOperationMarkdownForRoute(pageModel, route, locale); + return { description: pageModel.info.summary || pageModel.info.description || "", htmlPath: route, group: getDocSectionLabel(baseRoute, locale), kind: "wrapper", - markdown: buildOperationMarkdownForRoute(pageModel, route, locale), + markdownBody, + markdown: appendFastnearAiFooter(markdownBody, locale), markdownPath: buildMarkdownMirrorPath(route), markdownPaths: buildMarkdownMirrorAliases(route), route, @@ -1397,14 +1448,16 @@ function createAuthoredDocEntries(locale = DEFAULT_LOCALE) { }; } - const markdown = renderAuthoredMarkdown(content, route, relativePath, locale); + const markdownBody = renderAuthoredMarkdown(content, route, relativePath, locale); return { description: - data.description || getFirstMeaningfulParagraph(markdown).replace(/^\*\*Source:\*\*.+$/m, "").trim(), + data.description || + getFirstMeaningfulParagraph(markdownBody).replace(/^\*\*Source:\*\*.+$/m, "").trim(), htmlPath: route, group: getDocSectionLabel(baseRoute, locale), kind: "authored", - markdown, + markdownBody, + markdown: appendFastnearAiFooter(markdownBody, locale), markdownPath: buildMarkdownMirrorPath(route), markdownPaths: buildMarkdownMirrorAliases(route), route, @@ -1424,6 +1477,7 @@ function createCanonicalEntries(locale = DEFAULT_LOCALE) { const route = localizeRoute(baseRoute, locale); const topLevel = baseRoute.split("/")[1]; const groupKey = baseRoute.split("/")[2]; + const markdownBody = buildOperationMarkdownForRoute(localizedPageModel, route, locale); return { description: localizedPageModel.info.summary || localizedPageModel.info.description || "", @@ -1433,7 +1487,8 @@ function createCanonicalEntries(locale = DEFAULT_LOCALE) { : API_SERVICE_LABELS[locale]?.[groupKey] || API_SERVICE_LABELS[DEFAULT_LOCALE]?.[groupKey] || groupKey, htmlPath: route, kind: topLevel === "rpcs" ? "rpc" : "api", - markdown: buildOperationMarkdownForRoute(localizedPageModel, route, locale), + markdownBody, + markdown: appendFastnearAiFooter(markdownBody, locale), markdownPath: buildMarkdownMirrorPath(route), markdownPaths: buildMarkdownMirrorAliases(route), route, @@ -1682,10 +1737,10 @@ function buildFullArchive(entries, locale = DEFAULT_LOCALE) { `- ${labels.markdownPath}: ${buildAbsoluteUrl(entry.markdownPath)}`, "" ); - sections.push(entry.markdown.trim(), ""); + sections.push((entry.markdownBody || entry.markdown).trim(), ""); } - return `${normalizeMarkdown(sections.join("\n"))}\n`; + return appendFastnearAiFooter(sections.join("\n"), locale); } function main() { diff --git a/sidebars.js b/sidebars.js index 112192d..648be21 100644 --- a/sidebars.js +++ b/sidebars.js @@ -41,162 +41,220 @@ const nearcoreReleaseSidebarItems = ] : []; -const rpcSidebar = [ - ...nearcoreReleaseSidebarItems, - 'rpc/index', - 'auth/index', - { - type: 'category', - label: 'Account', - items: [ - 'rpc/account/view-account', - 'rpc/account/view-access-key', - 'rpc/account/view-access-key-list', - ], - }, - { - type: 'category', - label: 'Block', - items: [ - 'rpc/block/block-by-height', - 'rpc/block/block-by-id', - 'rpc/block/block-effects', - ], - }, - { - type: 'category', - label: 'Contract', - items: [ - 'rpc/contract/call-function', - 'rpc/contract/view-code', - 'rpc/contract/view-state', - 'rpc/contract/view-global-contract-code', - 'rpc/contract/view-global-contract-code-by-account-id', - ], - }, - { - type: 'category', - label: 'Protocol', - items: [ - 'rpc/protocol/status', - 'rpc/protocol/health', - 'rpc/protocol/gas-price', - 'rpc/protocol/gas-price-by-block', - 'rpc/protocol/genesis-config', - 'rpc/protocol/changes', - 'rpc/protocol/chunk-by-hash', - 'rpc/protocol/chunk-by-block-shard', - 'rpc/protocol/client-config', - 'rpc/protocol/network-info', - 'rpc/protocol/latest-block', - 'rpc/protocol/metrics', - 'rpc/protocol/maintenance-windows', - 'rpc/protocol/light-client-proof', - 'rpc/protocol/next-light-client-block', - 'rpc/protocol/experimental-protocol-config', - 'rpc/protocol/experimental-congestion-level', - 'rpc/protocol/experimental-light-client-block-proof', - 'rpc/protocol/experimental-light-client-proof', - 'rpc/protocol/experimental-split-storage-info', - ], - }, - { - type: 'category', - label: 'Transaction', - items: [ - 'rpc/transaction/tx-status', - 'rpc/transaction/send-tx', - 'rpc/transaction/broadcast-tx-async', - 'rpc/transaction/broadcast-tx-commit', - 'rpc/transaction/experimental-receipt', - 'rpc/transaction/experimental-tx-status', - ], - }, - { - type: 'category', - label: 'Validators', - items: [ - 'rpc/validators/validators-current', - 'rpc/validators/validators-by-epoch', - 'rpc/validators/experimental-validators-ordered', - ], - }, -]; - -const fastnearApiSidebar = [ - 'api/index', - { - type: 'category', - label: 'V0', - collapsible: false, - collapsed: false, - items: [ - 'api/v0-public-key', - 'api/v0-public-key-all', - 'api/v0-account-staking', - 'api/v0-account-ft', - 'api/v0-account-nft', - ], - }, - { +function makeExamplesDivider() { + return { + type: 'html', + value: '', + defaultStyle: false, + className: 'fastnear-sidebar-examples-divider', + }; +} + +function makeExamplesDoc(id) { + return { + type: 'doc', + id, + className: 'fastnear-sidebar-examples-link', + }; +} + +function makeExamplesCategory(id, items) { + return { type: 'category', - label: 'V1', - collapsible: false, + label: 'Examples', + link: { + type: 'doc', + id, + }, + items, collapsed: false, - items: [ - 'api/v1-public-key', - 'api/v1-public-key-all', - 'api/v1-account-staking', - 'api/v1-account-ft', - 'api/v1-account-nft', - 'api/v1-ft-top', - 'api/v1-account-full', - ], - }, - 'api/status', - 'api/health', -]; - -const transactionsApiSidebar = [ - 'tx/index', - 'tx/transactions', - 'tx/account', - 'tx/block', - 'tx/blocks', - 'tx/receipt', -]; + className: 'fastnear-sidebar-examples-category', + }; +} + +function makeExamplesFooterItem(config) { + if (typeof config === 'string') { + return makeExamplesDoc(config); + } + + return makeExamplesCategory(config.id, config.items); +} + +function withExamplesFooter(items, examplesConfig) { + return [...items, makeExamplesDivider(), makeExamplesFooterItem(examplesConfig)]; +} + +const rpcSidebar = withExamplesFooter( + [ + ...nearcoreReleaseSidebarItems, + 'rpc/index', + 'auth/index', + { + type: 'category', + label: 'Account', + items: [ + 'rpc/account/view-account', + 'rpc/account/view-access-key', + 'rpc/account/view-access-key-list', + ], + }, + { + type: 'category', + label: 'Block', + items: [ + 'rpc/block/block-by-height', + 'rpc/block/block-by-id', + 'rpc/block/block-effects', + ], + }, + { + type: 'category', + label: 'Contract', + items: [ + 'rpc/contract/call-function', + 'rpc/contract/view-code', + 'rpc/contract/view-state', + 'rpc/contract/view-global-contract-code', + 'rpc/contract/view-global-contract-code-by-account-id', + ], + }, + { + type: 'category', + label: 'Protocol', + items: [ + 'rpc/protocol/status', + 'rpc/protocol/health', + 'rpc/protocol/gas-price', + 'rpc/protocol/gas-price-by-block', + 'rpc/protocol/genesis-config', + 'rpc/protocol/changes', + 'rpc/protocol/chunk-by-hash', + 'rpc/protocol/chunk-by-block-shard', + 'rpc/protocol/client-config', + 'rpc/protocol/network-info', + 'rpc/protocol/latest-block', + 'rpc/protocol/metrics', + 'rpc/protocol/maintenance-windows', + 'rpc/protocol/light-client-proof', + 'rpc/protocol/next-light-client-block', + 'rpc/protocol/experimental-protocol-config', + 'rpc/protocol/experimental-congestion-level', + 'rpc/protocol/experimental-light-client-block-proof', + 'rpc/protocol/experimental-light-client-proof', + 'rpc/protocol/experimental-split-storage-info', + ], + }, + { + type: 'category', + label: 'Transaction', + items: [ + 'rpc/transaction/tx-status', + 'rpc/transaction/send-tx', + 'rpc/transaction/broadcast-tx-async', + 'rpc/transaction/broadcast-tx-commit', + 'rpc/transaction/experimental-receipt', + 'rpc/transaction/experimental-tx-status', + ], + }, + { + type: 'category', + label: 'Validators', + items: [ + 'rpc/validators/validators-current', + 'rpc/validators/validators-by-epoch', + 'rpc/validators/experimental-validators-ordered', + ], + }, + ], + 'rpc/examples' +); + +const fastnearApiSidebar = withExamplesFooter( + [ + 'api/index', + { + type: 'category', + label: 'V0', + collapsible: false, + collapsed: false, + items: [ + 'api/v0-public-key', + 'api/v0-public-key-all', + 'api/v0-account-staking', + 'api/v0-account-ft', + 'api/v0-account-nft', + ], + }, + { + type: 'category', + label: 'V1', + collapsible: false, + collapsed: false, + items: [ + 'api/v1-public-key', + 'api/v1-public-key-all', + 'api/v1-account-staking', + 'api/v1-account-ft', + 'api/v1-account-nft', + 'api/v1-ft-top', + 'api/v1-account-full', + ], + }, + 'api/status', + 'api/health', + ], + 'api/examples' +); + +const transactionsApiSidebar = withExamplesFooter( + [ + 'tx/index', + 'tx/transactions', + 'tx/account', + 'tx/block', + 'tx/blocks', + 'tx/receipt', + ], + 'tx/examples' +); const transfersApiSidebar = hideEarlyApiFamilies ? [] - : ['transfers/index', 'transfers/transfers']; - -const nearDataApiSidebar = [ - 'neardata/index', - 'neardata/first-block', - 'neardata/block', - 'neardata/block-headers', - 'neardata/block-chunk', - 'neardata/block-shard', - 'neardata/block-optimistic', - 'neardata/last-block-final', - 'neardata/last-block-optimistic', - 'neardata/health', -]; + : withExamplesFooter(['transfers/index', 'transfers/transfers'], 'transfers/examples'); + +const nearDataApiSidebar = withExamplesFooter( + [ + 'neardata/index', + 'neardata/first-block', + 'neardata/block', + 'neardata/block-headers', + 'neardata/block-chunk', + 'neardata/block-shard', + 'neardata/block-optimistic', + 'neardata/last-block-final', + 'neardata/last-block-optimistic', + 'neardata/health', + ], + 'neardata/examples' +); const kvFastDataSidebar = hideEarlyApiFamilies ? [] - : [ - 'fastdata/kv/index', - 'fastdata/kv/all-by-predecessor', - 'fastdata/kv/history-by-predecessor', - 'fastdata/kv/latest-by-predecessor', - 'fastdata/kv/history-by-account', - 'fastdata/kv/latest-by-account', - 'fastdata/kv/history-by-key', - 'fastdata/kv/multi', - 'fastdata/kv/get-history-key', - 'fastdata/kv/get-latest-key', - ]; + : withExamplesFooter( + [ + 'fastdata/kv/index', + 'fastdata/kv/all-by-predecessor', + 'fastdata/kv/history-by-predecessor', + 'fastdata/kv/latest-by-predecessor', + 'fastdata/kv/history-by-account', + 'fastdata/kv/latest-by-account', + 'fastdata/kv/history-by-key', + 'fastdata/kv/multi', + 'fastdata/kv/get-history-key', + 'fastdata/kv/get-latest-key', + ], + 'fastdata/kv/examples' + ); const sidebars = { rpcSidebar, @@ -206,7 +264,13 @@ const sidebars = { nearDataApiSidebar, kvFastDataSidebar, transactionFlowSidebar: [{ type: 'autogenerated', dirName: 'transaction-flow' }], - snapshotsSidebars: [{ type: 'autogenerated', dirName: 'snapshots' }], + snapshotsSidebars: [ + 'snapshots/index', + 'snapshots/mainnet', + 'snapshots/testnet', + makeExamplesDivider(), + makeExamplesDoc('snapshots/examples'), + ], }; export default sidebars; diff --git a/src/components/BerryClubLiveBoard/index.js b/src/components/BerryClubLiveBoard/index.js new file mode 100644 index 0000000..85b9bac --- /dev/null +++ b/src/components/BerryClubLiveBoard/index.js @@ -0,0 +1,225 @@ +import React, { useEffect, useState } from 'react'; + +import berryClubSnapshots from '@site/src/data/berryClubSnapshots.json'; +import styles from './styles.module.css'; + +const RPC_URL = 'https://rpc.mainnet.fastnear.com'; +const CONTRACT_ID = 'berryclub.ek.near'; +const BOARD_SIZE = 50; +const DEFAULT_FALLBACK_SNAPSHOT = + berryClubSnapshots.snapshots.find((snapshot) => snapshot.id === 'recent') || + null; + +function colorToHex(color) { + return `#${Number(color).toString(16).padStart(6, '0').slice(-6)}`; +} + +function encodeArgsBase64(args) { + return btoa(JSON.stringify(args)); +} + +function decodeJsonBytes(bytes) { + return JSON.parse(new TextDecoder().decode(Uint8Array.from(bytes))); +} + +function decodeLine(encodedLine) { + const binary = atob(encodedLine); + const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0)); + const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); + const colors = []; + + for (let offset = 4; offset + 4 <= bytes.length; offset += 8) { + colors.push(view.getUint32(offset, true) & 0xffffff); + } + + while (colors.length < BOARD_SIZE) { + colors.push(0); + } + + return colors.slice(0, BOARD_SIZE); +} + +function decodeBoard(lines) { + const decodedLines = lines.slice(0, BOARD_SIZE).map(decodeLine); + + while (decodedLines.length < BOARD_SIZE) { + decodedLines.push(Array(BOARD_SIZE).fill(0)); + } + + return decodedLines; +} + +async function fetchLiveBoard() { + const response = await fetch(RPC_URL, { + method: 'POST', + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 'berry-live-board', + method: 'query', + params: { + request_type: 'call_function', + finality: 'final', + account_id: CONTRACT_ID, + method_name: 'get_lines', + args_base64: encodeArgsBase64({ + lines: Array.from({ length: BOARD_SIZE }, (_, index) => index), + }), + }, + }), + }); + + if (!response.ok) { + throw new Error(`RPC request failed with ${response.status}`); + } + + const payload = await response.json(); + + if (payload.error) { + throw new Error(payload.error.message || 'RPC returned an error'); + } + + const result = payload.result; + + return { + board: decodeBoard(decodeJsonBytes(result.result)), + blockHeight: result.block_height, + blockHash: result.block_hash, + }; +} + +function Board({ board, title }) { + return ( +
+ {board.flat().map((color, index) => ( +
+ ))} +
+ ); +} + +export default function BerryClubLiveBoard({ + fallbackSnapshot, + title, + uiText = {}, +}) { + const resolvedFallbackSnapshot = fallbackSnapshot || DEFAULT_FALLBACK_SNAPSHOT; + const resolvedUiText = { + title: uiText.title || 'Live Berry Club board', + blockHeightLabel: uiText.blockHeightLabel || 'Block', + blockHashLabel: uiText.blockHashLabel || 'Block hash', + sourceLabel: uiText.sourceLabel || 'Source', + sourceValue: uiText.sourceValue || 'Mainnet RPC `get_lines`', + loadingLabel: uiText.loadingLabel || 'Loading live board...', + refreshingLabel: + uiText.refreshingLabel || 'Refreshing live board from RPC...', + fallbackLabel: + uiText.fallbackLabel || + 'Showing the latest saved snapshot while the live RPC read updates.', + errorLabel: uiText.errorLabel || 'Live RPC read failed.', + emptyLabel: uiText.emptyLabel || 'No board data available yet.', + }; + + const [board, setBoard] = useState(resolvedFallbackSnapshot?.board || null); + const [blockHeight, setBlockHeight] = useState( + resolvedFallbackSnapshot?.blockHeight || null + ); + const [blockHash, setBlockHash] = useState(null); + const [status, setStatus] = useState( + resolvedFallbackSnapshot ? 'refreshing' : 'loading' + ); + const [error, setError] = useState(null); + + useEffect(() => { + let active = true; + + fetchLiveBoard() + .then((result) => { + if (!active) { + return; + } + + setBoard(result.board); + setBlockHeight(result.blockHeight); + setBlockHash(result.blockHash); + setStatus('ready'); + setError(null); + }) + .catch((fetchError) => { + if (!active) { + return; + } + + setError(fetchError.message); + setStatus(resolvedFallbackSnapshot ? 'fallback' : 'error'); + }); + + return () => { + active = false; + }; + }, [resolvedFallbackSnapshot]); + + return ( +
+
+
+

{title || resolvedUiText.title}

+
+
+
{resolvedUiText.sourceLabel}
+
{resolvedUiText.sourceValue}
+
+ {blockHeight ? ( +
+
{resolvedUiText.blockHeightLabel}
+
{blockHeight}
+
+ ) : null} + {blockHash ? ( +
+
{resolvedUiText.blockHashLabel}
+
{blockHash}
+
+ ) : null} +
+
+ +
+ {status === 'loading' ? ( +

{resolvedUiText.loadingLabel}

+ ) : null} + {status === 'refreshing' ? ( + <> +

{resolvedUiText.refreshingLabel}

+

{resolvedUiText.fallbackLabel}

+ + ) : null} + {status === 'fallback' ? ( + <> +

{resolvedUiText.errorLabel}

+

{resolvedUiText.fallbackLabel}

+ + ) : null} + {status === 'error' ? ( + <> +

{resolvedUiText.errorLabel}

+ {error ?

{error}

: null} + + ) : null} +
+
+ + {board ? ( + + ) : ( +
{resolvedUiText.emptyLabel}
+ )} +
+ ); +} diff --git a/src/components/BerryClubLiveBoard/styles.module.css b/src/components/BerryClubLiveBoard/styles.module.css new file mode 100644 index 0000000..cc88701 --- /dev/null +++ b/src/components/BerryClubLiveBoard/styles.module.css @@ -0,0 +1,106 @@ +.card { + background: + linear-gradient(180deg, rgba(255, 248, 240, 0.96), rgba(255, 255, 255, 0.98)); + border: 1px solid rgba(170, 140, 116, 0.35); + border-radius: 16px; + box-shadow: 0 18px 48px rgba(83, 52, 28, 0.12); + margin: 1.5rem 0; + padding: 1rem; +} + +.cardHeader { + display: grid; + gap: 1rem; + margin-bottom: 1rem; +} + +@media (min-width: 780px) { + .cardHeader { + align-items: start; + grid-template-columns: minmax(0, 1fr) minmax(220px, 280px); + } +} + +.cardTitle { + font-size: 1.15rem; + line-height: 1.2; + margin: 0 0 0.75rem; +} + +.metaList { + display: grid; + gap: 0.35rem; + margin: 0; +} + +.metaItem { + align-items: baseline; + display: grid; + gap: 0.35rem; + grid-template-columns: minmax(72px, auto) 1fr; +} + +.metaItem dt { + color: rgba(92, 67, 48, 0.78); + font-size: 0.78rem; + font-weight: 600; + margin: 0; +} + +.metaItem dd { + color: rgba(33, 23, 15, 0.96); + font-family: var(--ifm-font-family-monospace); + font-size: 0.78rem; + margin: 0; + overflow-wrap: anywhere; +} + +.hashValue { + word-break: break-word; +} + +.statusBlock { + display: grid; + gap: 0.35rem; +} + +.status { + color: rgba(92, 67, 48, 0.96); + font-size: 0.88rem; + font-weight: 600; + margin: 0; +} + +.helper { + color: rgba(92, 67, 48, 0.82); + font-size: 0.82rem; + margin: 0; +} + +.board { + background: #0f0d08; + border: 1px solid rgba(22, 16, 10, 0.65); + border-radius: 12px; + display: grid; + grid-template-columns: repeat(50, minmax(0, 1fr)); + overflow: hidden; + width: 100%; +} + +.pixel { + aspect-ratio: 1 / 1; + min-width: 0; +} + +.emptyBoard { + align-items: center; + background: rgba(15, 13, 8, 0.05); + border: 1px dashed rgba(92, 67, 48, 0.35); + border-radius: 12px; + color: rgba(92, 67, 48, 0.82); + display: flex; + justify-content: center; + min-height: 240px; + padding: 1rem; + text-align: center; +} diff --git a/src/components/BerryClubSnapshotGallery/index.js b/src/components/BerryClubSnapshotGallery/index.js new file mode 100644 index 0000000..a3957ef --- /dev/null +++ b/src/components/BerryClubSnapshotGallery/index.js @@ -0,0 +1,70 @@ +import React from 'react'; + +import styles from './styles.module.css'; + +function colorToHex(color) { + return `#${Number(color).toString(16).padStart(6, '0').slice(-6)}`; +} + +function SnapshotCard({ snapshot, label, uiText }) { + const hashPreview = `${snapshot.txHash.slice(0, 8)}...${snapshot.txHash.slice(-8)}`; + + return ( +
+
+

{label}

+
+
+
{uiText.blockHeightLabel}
+
{snapshot.blockHeight}
+
+
+
{uiText.timestampLabel}
+
{snapshot.timestamp}
+
+
+
{uiText.txHashLabel}
+
+ {hashPreview} +
+
+
+
+ +
+ {snapshot.board.flat().map((color, index) => ( +
+ ))} +
+
+ ); +} + +export default function BerryClubSnapshotGallery({ + snapshots, + labels = {}, + uiText = {}, +}) { + const resolvedUiText = { + blockHeightLabel: uiText.blockHeightLabel || 'Block', + timestampLabel: uiText.timestampLabel || 'Time', + txHashLabel: uiText.txHashLabel || 'Transaction', + }; + + return ( +
+ {snapshots.map((snapshot) => ( + + ))} +
+ ); +} diff --git a/src/components/BerryClubSnapshotGallery/styles.module.css b/src/components/BerryClubSnapshotGallery/styles.module.css new file mode 100644 index 0000000..0688604 --- /dev/null +++ b/src/components/BerryClubSnapshotGallery/styles.module.css @@ -0,0 +1,71 @@ +.gallery { + display: grid; + gap: 1.25rem; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + margin: 1.5rem 0; +} + +.card { + background: + linear-gradient(180deg, rgba(255, 248, 240, 0.96), rgba(255, 255, 255, 0.98)); + border: 1px solid rgba(170, 140, 116, 0.35); + border-radius: 16px; + box-shadow: 0 18px 48px rgba(83, 52, 28, 0.12); + padding: 1rem; +} + +.cardHeader { + margin-bottom: 0.85rem; +} + +.cardTitle { + font-size: 1rem; + line-height: 1.2; + margin: 0 0 0.75rem; +} + +.metaList { + display: grid; + gap: 0.35rem; + margin: 0; +} + +.metaItem { + align-items: baseline; + display: grid; + gap: 0.35rem; + grid-template-columns: minmax(72px, auto) 1fr; +} + +.metaItem dt { + color: rgba(92, 67, 48, 0.78); + font-size: 0.78rem; + font-weight: 600; + margin: 0; +} + +.metaItem dd { + color: rgba(33, 23, 15, 0.96); + font-family: var(--ifm-font-family-monospace); + font-size: 0.78rem; + margin: 0; +} + +.hashValue { + overflow-wrap: anywhere; +} + +.board { + background: #0f0d08; + border: 1px solid rgba(22, 16, 10, 0.65); + border-radius: 12px; + display: grid; + grid-template-columns: repeat(50, minmax(0, 1fr)); + overflow: hidden; + width: 100%; +} + +.pixel { + aspect-ratio: 1 / 1; + min-width: 0; +} diff --git a/src/css/custom.css b/src/css/custom.css index 1b65d21..b0e2ee0 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -477,6 +477,35 @@ pre code { background: rgba(243, 245, 255, 0.12); } +.theme-doc-sidebar-item-link.fastnear-sidebar-examples-divider, +.navbar-sidebar .fastnear-sidebar-examples-divider { + list-style: none; + margin: 1rem 0 0; + padding: 0; + pointer-events: none; +} + +.theme-doc-sidebar-item-link.fastnear-sidebar-examples-divider > div, +.navbar-sidebar .fastnear-sidebar-examples-divider > div { + border-top: 1px solid rgba(17, 17, 17, 0.08); + margin: 0 1rem; +} + +.theme-doc-sidebar-item-link.fastnear-sidebar-examples-link, +.navbar-sidebar .fastnear-sidebar-examples-link { + margin-top: 0.35rem; +} + +.theme-doc-sidebar-item-category.fastnear-sidebar-examples-category, +.navbar-sidebar .fastnear-sidebar-examples-category { + margin-top: 0.35rem; +} + +[data-theme='dark'] .theme-doc-sidebar-item-link.fastnear-sidebar-examples-divider > div, +[data-theme='dark'] .navbar-sidebar .fastnear-sidebar-examples-divider > div { + border-top-color: rgba(243, 245, 255, 0.12); +} + /* Swap toggle icons: show destination mode instead of current mode */ [data-theme-choice='light'] [class*='lightToggleIcon'] { display: none !important; @@ -1665,6 +1694,95 @@ html[data-theme='light'] .fastnear-home-button--primary:focus-visible { text-decoration: none; } +.fastnear-example-strategy { + margin: 1rem 0 1.35rem; + padding: 16px 18px; + border: 1px solid rgb(15 23 42 / 8%); + border-radius: 18px; + background: + linear-gradient(180deg, rgb(255 255 255 / 94%), rgb(244 247 255 / 98%)); + box-shadow: 0 10px 24px rgb(15 23 42 / 6%); +} + +.fastnear-example-strategy__header { + display: grid; + gap: 6px; + margin-bottom: 10px; +} + +.fastnear-example-strategy__eyebrow { + display: inline-flex; + align-items: center; + width: fit-content; + padding: 3px 8px; + border: 1px solid rgb(15 86 179 / 14%); + border-radius: 999px; + background: rgb(255 255 255 / 72%); + color: #3654a8; + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.fastnear-example-strategy__title { + margin: 0; + color: #14213d; + font-size: 1rem; + font-weight: 700; + line-height: 1.45; +} + +.fastnear-example-strategy__items { + display: grid; + gap: 8px; +} + +.fastnear-example-strategy__item { + display: grid; + grid-template-columns: auto minmax(0, 1fr); + align-items: start; + gap: 10px; + margin: 0; + padding: 10px 12px; + border: 1px solid rgb(54 84 168 / 10%); + border-radius: 12px; + background: rgb(255 255 255 / 58%); + color: #42526f; + line-height: 1.6; +} + +.fastnear-example-strategy__step { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 2rem; + height: 2rem; + border: 1px solid rgb(15 86 179 / 14%); + border-radius: 10px; + background: linear-gradient(180deg, rgb(255 255 255 / 86%), rgb(224 231 255 / 86%)); + color: #3654a8; + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.06em; +} + +.fastnear-example-strategy__item span:last-child { + min-width: 0; +} + +.fastnear-example-strategy__code { + white-space: nowrap; +} + +.fastnear-example-strategy__code { + padding: 0.12rem 0.38rem; + border: 1px solid rgb(54 84 168 / 10%); + border-radius: 8px; + background: rgb(255 255 255 / 72%); + color: #233252; +} + .fastnear-home-hero__panel { display: grid; align-content: start; @@ -1997,6 +2115,41 @@ html[data-theme='light'] .fastnear-home-button--primary:focus-visible { color: #ffffff; } +[data-theme='dark'] .fastnear-example-strategy { + border-color: rgb(148 163 184 / 20%); + background: + linear-gradient(180deg, rgb(30 41 59 / 96%), rgb(26 35 50 / 98%)); + box-shadow: 0 18px 34px rgb(0 0 0 / 22%); +} + +[data-theme='dark'] .fastnear-example-strategy__eyebrow { + border-color: rgb(148 163 184 / 26%); + background: rgb(15 23 42 / 56%); + color: #c4d3ff; +} + +[data-theme='dark'] .fastnear-example-strategy__title { + color: #f3f5ff; +} + +[data-theme='dark'] .fastnear-example-strategy__item { + border-color: rgb(148 163 184 / 18%); + background: rgb(15 23 42 / 34%); + color: rgb(226 232 240 / 86%); +} + +[data-theme='dark'] .fastnear-example-strategy__step { + border-color: rgb(148 163 184 / 20%); + background: linear-gradient(180deg, rgb(15 23 42 / 82%), rgb(30 41 59 / 88%)); + color: #c4d3ff; +} + +[data-theme='dark'] .fastnear-example-strategy__code { + border-color: rgb(148 163 184 / 18%); + background: rgb(15 23 42 / 62%); + color: #e8eefc; +} + [data-theme='dark'] .fastnear-home-route-card__title { color: #98c7fd; } diff --git a/src/data/berryClubSnapshots.json b/src/data/berryClubSnapshots.json new file mode 100644 index 0000000..84c9ff5 --- /dev/null +++ b/src/data/berryClubSnapshots.json @@ -0,0 +1 @@ +{"generatedAt":"2026-04-18T23:00:41.902Z","network":"mainnet","contractId":"berryclub.ek.near","boardSize":50,"snapshots":[{"id":"launch","label":"Launch era","txHash":"BDNFpCpLXjBrgjR6z6wCZmB9EWdHnVMdqau3iTWTRE5H","blockHeight":21898354,"timestamp":"2020-11-08T01:18:58.488Z","timestampNs":"1604798338488044956","signerId":"kmpec.near","pixelCount":1,"board":[[11184810,6749952,6749952,6749952,6749952,16622079,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6710886,16622079,16683520,16683520,16683520,16683520,16683520,6710886,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,982784,6749952,6749952,6749952],[11184810,16622079,16622079,16622079,10421504,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,10421504,7592191,7592191,11184810,7592191,7592191,10421504,10421504,10421504,16683520,16683520,16683520,16683520,16683520,16683520,16683520,16683520,16683520,6749952,16683520,6749952,16683520,6749952,6749952,6749952,6749952,16394495,16394495,11184810,11184810,11184810,11184810,11184810,11184810,25265,6749952],[11184810,11184810,11184810,11184810,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,7592191,16622079,16622079,7592191,16622079,16622079,7592191,11184810,11184810,16622079,16622079,11184810,16622079,16622079,11184810,16622079,16622079,16622079,11184810,16622079,16622079,6749952,11184810,16622079,16683520,11184810,16683520,16394495,11184810,16622079,16622079,16622079,11184810,16622079,25265,6749952],[11184810,11184810,11184810,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,7592191,16622079,16622079,16622079,16622079,16622079,7592191,16622079,6710886,0,11184810,16622079,6710886,16622079,6710886,16622079,16622079,0,6710886,16622079,6710886,0,16394495,16622079,0,0,16622079,16394495,11184810,16683520,11184810,16622079,11184810,11184810,25265,6749952],[11184810,11184810,6749952,6749952,6863872,6863872,6863872,6863872,6863872,6749952,6863872,6863872,6863872,6863872,6749952,7592191,16622079,16622079,16622079,7592191,40160,0,0,0,0,0,0,16622079,11184810,6710886,16622079,11184810,11184810,16683520,11184810,11184810,11184810,6710886,6710886,16711740,16394495,16622079,11184810,6710886,16683520,16683520,11184810,11184810,25265,6749952],[11184810,11184810,11184810,6749952,16777215,16777215,16777215,0,16777215,6749952,16777215,16777215,13840661,0,6749952,11184810,7592191,16622079,7592191,40160,40160,0,0,0,0,0,6749952,0,16622079,11184810,0,16683520,16394495,11184810,16394495,11184810,12865792,12865792,12865792,16394495,16394495,16683520,11184810,16622079,11184810,16622079,11184810,16711740,25265,6749952],[11184810,11184810,11184810,6749952,6749952,16777215,16777215,0,16711740,6749952,2507776,16777215,16777215,0,6749952,11184810,11184810,7592191,6710886,6710886,6710886,6749952,0,6749952,6710886,6749952,6749952,11184810,16622079,10421504,16394495,16394495,11184810,11184810,16394495,12865792,11184810,11184810,11184810,6863872,6863872,11184810,11184810,11184810,11184810,11184810,16683520,11184810,25265,6749952],[11184810,11184810,6749952,6749952,6863872,6863872,6863872,6749952,6863872,6749952,6863872,6749952,6749952,6749952,6749952,11184810,11184810,11184810,6710886,16622079,16622079,6710886,16571392,16622079,11184810,6710886,11184810,16565248,6710886,11184810,6710886,11184810,10804480,11184810,11184810,11184810,11184810,6863872,6863872,11660800,11660800,6863872,11184810,11184810,11184810,11184810,16711740,16683520,25265,6749952],[11184810,11184810,11184810,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,6749952,11184810,11184810,11184810,6710886,16622079,6710886,6710886,16711740,6710886,6710886,6710886,11184810,16683520,16683520,11184810,11184810,11184810,11184810,11184810,11184810,6863872,6863872,11660800,11660800,11660800,11660800,11660800,6863872,11184810,11184810,11184810,11184810,16683520,11184810,6749952],[11184810,11184810,11184810,16683520,0,0,0,0,6749952,6749952,6749952,0,0,0,0,11184810,11184810,11184810,11184810,6710886,6749952,6710886,6749952,1900799,6710886,0,11184810,0,16394495,11184810,11184810,11184810,11184810,11184810,11184810,6863872,11660800,11660800,11660800,11660800,11660800,11660800,11660800,6863872,11184810,11184810,11184810,11184810,11184810,6749952],[11184810,11184810,11184810,11184810,16683520,16010811,16683520,16711740,16683520,6749952,16683520,16683520,16683520,16683520,16683520,11184810,11184810,11184810,11184810,6749952,6749952,6749952,0,13840661,6868170,11184810,6710886,11184810,0,11184810,11184810,11184810,11184810,11184810,6863872,6863872,11660800,11660800,11660800,11660800,11660800,11660800,11660800,6863872,11184810,11184810,16683520,11184810,11184810,6749952],[11184810,11184810,11184810,11184810,11184810,11184810,11184810,6863872,6863872,6749952,6863872,6863872,6863872,11184810,11184810,11184810,11184810,11184810,6868170,6749952,6749952,6749952,6749952,0,6710886,6710886,6710886,0,6710886,11184810,11184810,11184810,11184810,6863872,11660800,11660800,11660800,11660800,11660800,11660800,11660800,11660800,11660800,6863872,11184810,11184810,16683520,11184810,11184810,6749952],[11184810,11184810,11184810,11184810,11184810,11184810,6749952,6749952,6749952,6749952,6749952,6749952,6749952,11184810,11184810,11184810,11184810,11184810,6749952,6749952,6749952,6749952,0,6868170,11184810,0,0,0,11184810,11184810,11184810,11184810,6863872,11660800,11660800,11660800,11660800,3342336,16565248,16565248,11660800,11660800,11660800,6863872,11184810,11184810,11184810,11184810,0,6749952],[11184810,11184810,11184810,11184810,11184810,11184810,6749952,4481535,6749952,6749952,6749952,4481535,6749952,6749952,11184810,11184810,11184810,6749952,6749952,11184810,6749952,0,6749952,16683520,0,0,6868170,11184810,10804480,11184810,11184810,6863872,6863872,11660800,11660800,12865792,16683520,16683520,10421504,10421504,11660800,11660800,11660800,6863872,11184810,11184810,0,16711740,0,6749952],[11184810,11184810,11184810,11184810,6749952,6749952,6749952,4481535,4481535,6749952,6749952,4481535,6749952,6749952,6749952,11184810,6749952,6749952,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,6863872,11660800,11660800,11660800,10421504,12865792,16683520,16683520,12865792,11660800,11660800,6863872,8423680,11184810,11184810,11184810,0,7592191,6749952],[11184810,11184810,6749952,6749952,6749952,6749952,6749952,4481535,6749952,4481535,6749952,4481535,6749952,6749952,11184810,6749952,6749952,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,6863872,11660800,11660800,0,16683520,12865792,12865792,12865792,0,11660800,11660800,6863872,8423680,11184810,11184810,12865792,0,0,6749952],[11184810,11184810,11184810,11184810,6749952,6749952,6749952,4481535,6749952,6749952,4481535,4481535,6749952,6749952,11184810,6749952,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,6863872,11660800,11660800,0,12865792,3342336,3342336,0,12865792,11660800,11660800,6863872,8423680,11184810,11184810,8086783,7592191,0,6749952],[11184810,11184810,11184810,11184810,0,6749952,6749952,4481535,6749952,6749952,6749952,4481535,6749952,6749952,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,8423680,6863872,11660800,0,16565248,12865792,12865792,0,16565248,11660800,6863872,8423680,8423680,11184810,11184810,8086783,8086783,0,6749952],[11184810,11184810,6749952,6749952,6749952,6710886,6749952,6749952,6749952,16711680,6749952,6749952,6749952,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,8423680,6863872,11660800,12865792,0,12865792,0,16683520,11660800,11660800,6863872,8423680,11184810,11184810,11184810,12865792,11184810,6868170,6749952],[11184810,11184810,11184810,11184810,6749952,6749952,11184810,6749952,6749952,16711680,6749952,6749952,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,8423680,6863872,11660800,0,12865792,0,16683520,11660800,6863872,8423680,8423680,11184810,11184810,11184810,11184810,11184810,0,6749952],[11184810,11184810,11184810,6749952,6749952,6749952,11184810,6749952,0,11184810,0,6749952,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,8423680,6863872,11660800,11660800,11660800,11660800,11660800,11660800,6863872,8423680,8423680,11184810,11184810,11184810,8086783,6868170,0,6749952],[11184810,11184810,11184810,11184810,6749952,11184810,11184810,6749952,16565248,16711680,0,6749952,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,8423680,6863872,6863872,6863872,6863872,6863872,6863872,8423680,8423680,11184810,11184810,11184810,11184810,8086783,0,0,6749952],[11184810,11184810,11184810,11184810,11184810,11184810,11184810,6749952,6710886,16711680,0,6749952,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,8423680,8423680,8423680,8423680,8423680,8423680,8423680,8423680,8423680,11184810,11184810,11184810,11184810,8086783,11184810,6868170,6749952],[11184810,11184810,11184810,11184810,11184810,11184810,11184810,6749952,0,0,6868170,6749952,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,11184810,8423680,8423680,8423680,8423680,8423680,8423680,12865792,12865792,11184810,11184810,11184810,11184810,0,6868170,6868170,6749952],[11184810,11184810,11184810,11184810,6749952,6749952,6749952,6749952,0,0,0,6749952,6749952,6749952,6749952,0,6868170,6868170,0,0,16565248,8423680,16565248,0,0,0,16711684,16565248,0,0,0,6710886,16565248,11184810,6868170,16565248,6868170,6868170,16565248,0,6710886,0,6868170,6868170,6868170,0,0,6868170,0,6749952],[16622079,6710886,6868170,0,6749952,6749952,6749952,6749952,16777215,0,6868170,6749952,6749952,6749952,6749952,0,0,0,0,0,0,16565248,6868170,16565248,0,6868170,0,6868170,0,11582464,0,6868170,16565248,16565248,6868170,12865792,11582464,0,11582464,11184810,6868170,11184810,0,0,0,0,0,0,11184810,6749952],[16683520,6868170,6868170,16777215,6868170,16565248,6868170,6868170,0,0,0,0,0,7592191,0,0,0,0,0,0,0,6868170,16565248,16565248,16711684,6868170,6868170,0,16565248,11184810,6868170,0,16565248,6710886,11582464,12865792,16711684,1484197,0,11582464,1484197,11582464,6868170,0,0,1484197,16565248,1484197,16565248,6749952],[8423680,12865792,0,0,6868170,16565248,1228,8423680,0,6868170,7592191,0,0,0,0,0,0,0,6868170,0,16565248,6868170,16777215,16565248,16711684,0,16565248,6868170,11444735,6868170,16394495,0,11582464,6868170,16394495,16394495,16394495,0,16394495,11582464,1484197,1484197,1484197,1484197,6868170,0,1484197,16565248,0,1484197],[16565248,8423680,0,0,1228,0,0,7592191,6868170,0,0,0,8423680,0,8423680,0,8423680,0,6868170,16565248,14409472,16565248,6868170,16565248,16777215,16711684,6868170,6868170,0,16777215,6868170,0,6710886,6710886,6868170,1484197,16565248,6868170,6868170,1484197,6868170,11582464,6868170,6868170,11444735,6868170,16565248,16565248,16565248,6749952],[16565248,16565248,0,0,1228,16565248,0,16777215,0,6868170,0,0,0,0,0,16010811,6868170,0,0,16010811,16565248,0,16777215,0,16565248,0,16565248,16565248,16565248,0,0,10421504,10421504,6868170,10421504,6868170,6868170,16565248,11444735,11444735,11444735,11582464,11444735,6868170,6868170,6868170,0,16565248,16565248,6749952],[16683520,16565248,0,8423680,16565248,16565248,0,6868170,7592191,7592191,0,6868170,16489984,6868170,6868170,6868170,0,16565248,16565248,6868170,16565248,0,0,0,0,16565248,0,6868170,16777215,16565248,11444735,16565248,6868170,11444735,11444735,0,6868170,16565248,6710886,11582464,11444735,6868170,6868170,16777215,16565248,16565248,16565248,0,16565248,6749952],[6632084,16565248,16777215,16565248,0,6868170,0,0,0,0,0,16489984,6632084,0,0,6868170,6868170,6868170,6868170,6868170,6868170,16565248,0,6868170,6868170,6632084,10421504,6868170,11582464,6868170,6868170,16565248,16565248,16565248,16565248,6868170,11444735,0,16565248,0,0,0,11444735,0,16565248,16565248,16565248,16565248,0,16683520],[16683520,6868170,6868170,16565248,16565248,6868170,0,0,6868170,0,0,16565248,16489984,0,16777215,6868170,6868170,6868170,16565248,6868170,16565248,16489984,16565248,16565248,16711684,16711684,16711684,6868170,6868170,6868170,11582464,16565248,16565248,6868170,6868170,6868170,6868170,11444735,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,0,6710886],[6868170,8423680,16777215,6868170,0,6868170,6868170,6868170,16565248,0,0,0,0,16489984,6868170,6868170,16565248,6868170,16565248,0,6868170,6868170,0,0,10421504,11444735,0,0,0,6868170,11582464,6868170,6868170,16565248,11444735,6868170,6710886,11444735,16777215,16565248,16565248,16565248,16565248,0,0,0,16565248,16565248,16777215,1658163],[16622079,6868170,6868170,6868170,0,6868170,0,6868170,6868170,16565248,0,0,0,16565248,6868170,16565248,16571392,16565248,16565248,14409472,6868170,6868170,16565248,11444735,0,16565248,0,16565248,11582464,16565248,0,0,11444735,16565248,16565248,16565248,16565248,11444735,10421504,16565248,16565248,16565248,0,16571392,16571392,0,16565248,16565248,16565248,16683520],[16010811,16565248,16565248,16565248,0,0,16565248,0,0,0,0,6868170,16489984,6868170,16489984,6868170,16565248,6868170,6868170,16777215,0,0,11444735,0,7592191,7592191,0,0,6868170,7592191,6710886,11582464,11444735,0,12865792,11444735,11444735,16565248,0,16565248,16565248,16565248,0,16571392,16571392,0,16565248,16565248,16565248,6710886],[16010811,6868170,6868170,6868170,0,0,16565248,6868170,16565248,16489984,16489984,16489984,11211934,16489984,16489984,16489984,0,6868170,16489984,16489984,6868170,16565248,16489984,11444735,6710886,0,7592191,16565248,11582464,16565248,0,0,11444735,11444735,0,0,11582464,11582464,0,16565248,16565248,16565248,0,16571392,16571392,16571392,0,16565248,16565248,16683520],[16010811,25265,25265,25265,25265,0,16565248,25265,16565248,16565248,16565248,16565248,16565248,16565248,0,0,16565248,16565248,11211934,16565248,10421504,0,0,16777215,11211934,16565248,16565248,0,11582464,0,16565248,0,0,11582464,11582464,0,11444735,16565248,10421504,16565248,16565248,16565248,0,16571392,16571392,16571392,0,16565248,16565248,6868170],[16010811,25265,25265,25265,16489984,16489984,16489984,25265,16489984,16565248,16565248,16565248,16489984,0,0,0,0,0,16565248,0,6632084,6632084,6632084,6632084,6632084,6632084,11444735,0,11582464,0,0,11444735,10421504,11444735,16565248,10421504,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16711933,16571392,16565248,0],[25265,25265,25265,25265,16489984,16565248,25265,16565248,25265,25265,16622079,16622079,16622079,16622079,16622079,16622079,16622079,16565248,0,6632084,6632084,6868170,16571392,6632084,6632084,6632084,16565248,6710886,16565248,0,0,0,0,0,16565248,10421504,16565248,16565248,16565248,16565248,16565248,0,16571392,16571392,16571392,16571392,0,16565248,16565248,16622079],[6868170,16489984,25265,25265,16489984,25265,25265,6868170,6868170,6868170,16489984,16622079,6868170,16565248,25265,0,16622079,0,16565248,6868170,6632084,0,0,0,6632084,0,16565248,0,0,16777215,10421504,6868170,0,0,10421504,16565248,16565248,16565248,16565248,16565248,0,0,16571392,16571392,16571392,16571392,0,16565248,16565248,7592191],[0,0,0,6868170,0,25265,25265,16622079,0,16622079,25265,0,6868170,6868170,0,6868170,16622079,6868170,16777215,6632084,0,16565248,6868170,6632084,0,6868170,2277887,0,6868170,6868170,2277887,0,0,7592191,16565248,16565248,16565248,16565248,16565248,0,16571392,16571392,16571392,16571392,16571392,16571392,0,16565248,16565248,16777215],[13377024,13377024,13377024,0,13377024,16622079,13377024,0,0,13377024,0,6868170,13377024,6868170,6868170,6868170,16622079,6868170,6632084,6632084,6632084,16571392,6868170,16489984,6632084,16565248,16565248,0,0,6868170,16565248,6868170,7592191,7592191,16565248,16565248,16565248,0,0,16571392,16571392,16571392,16571392,16571392,16571392,0,16565248,16565248,16565248,16622079],[6868170,13377024,13377024,6868170,13377024,16622079,16622079,6868170,6868170,13377024,6868170,0,0,6868170,0,6868170,0,0,6632084,16565248,6632084,6632084,6632084,6632084,6632084,2277887,2277887,0,7592191,2277887,7592191,6868170,7592191,10421504,16565248,16565248,0,16571392,16571392,16571392,16571392,16571392,16571392,16571392,0,16565248,16565248,16565248,16565248,7592191],[13377024,6868170,13377024,0,0,6868170,13377024,6868170,0,6868170,13377024,6868170,6868170,0,16622079,16565248,16622079,0,6632084,6632084,6632084,6632084,2277887,16565248,16565248,0,10421504,7592191,0,7592191,0,0,16565248,16565248,16565248,16565248,0,16571392,16571392,16571392,16571392,16571392,0,0,16565248,16565248,16565248,16565248,16565248,16622079],[13377024,0,0,16622079,13377024,6868170,13377024,6868170,13377024,13377024,6868170,6868170,6868170,6868170,13377024,16565248,16565248,16565248,16565248,16565248,6632084,16571392,0,10421504,2277887,10421504,0,10421504,0,10421504,0,10421504,7592191,16565248,16565248,16565248,16565248,0,0,0,0,0,16565248,16565248,16565248,16565248,16565248,16565248,16777215,0],[13377024,13377024,13377024,16622079,13377024,13377024,13377024,13377024,13377024,13377024,13377024,13377024,16622079,6868170,13377024,16622079,11184810,11184810,11184810,16565248,16565248,8912896,16565248,16565248,2277887,10421504,2277887,2277887,2277887,2277887,8912896,2277887,8912896,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16711933,16571392,16565248,0],[0,0,2277887,16622079,7935,2277887,2277887,2277887,2277887,2277887,16622079,16622079,4508671,40160,7592191,0,0,0,11184810,8912896,8912896,16565248,16565248,16565248,2277887,2277887,2277887,2277887,2277887,8912896,2277887,2277887,16571392,16571392,16777215,16571392,16571392,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,16565248,0,0],[0,0,2277887,16010811,2277887,2277887,2277887,2277887,2277887,2277887,16622079,16622079,2277887,2277887,2277887,16711686,16711686,16711686,11184810,16565248,16565248,16565248,16565248,16565248,11211934,10421504,10421504,2277887,10421504,8912896,8912896,8912896,16571392,16777215,16571392,16565248,16565248,16565248,16565248,16565248,16565248,16571392,16565248,16565248,7935,16571392,16565248,16622079,0,0],[0,0,2277887,16622079,16622079,2277887,2277887,16772846,2277887,2277887,16622079,2277887,2277887,2277887,2277887,16571392,16571392,16571392,8912896,8912896,16565248,16565248,16622079,16565248,11211934,16565248,16565248,16565248,16565248,16565248,16622079,2277887,16571392,16565248,16565248,16565248,16565248,16565248,16571392,16777215,16565248,16565248,16565248,16565248,16571392,16571392,0,0,0,0]]},{"id":"mid","label":"Mid-era","txHash":"Hq5qwsuiM2emJrqczWM9awCa7o6sTBYqYpcifUX2SUhQ","blockHeight":97601515,"timestamp":"2023-07-29T10:41:41.009Z","timestampNs":"1690627301009685032","signerId":"1241q.near","pixelCount":72,"board":[[11789332,16645629,16777215,16711422,16710394,16710394,16775159,16776187,16776187,2827300,16710394,16643573,7104616,11328277,6908265,7895146,7697512,16776187,16776187,16777215,16776187,16776187,16777215,16776187,16775159,7104616,8946049,7630959,7894888,1966301,7960681,7565166,16710394,1966301,1966301,1966301,1966301,1966301,1966301,1966301,8288890,16710394,16776187,16710394,1966301,16776187,8287862,16571392,1446418,1314832],[7895144,7631988,16776187,16775159,8353655,7499374,8745584,16643573,16774388,16774388,16776187,16775159,16776187,16774388,16774388,16776187,16775159,16775159,16776187,16709366,16776187,16711422,7763559,8223097,16776187,16578808,16579836,16776187,16775159,1966301,1966301,16710394,1966301,1966301,1966301,16710394,1966301,7895146,1966301,1966301,1966301,6250335,1966301,16577780,1966301,1966301,16775159,16571392,6381921,1643797],[7083444,16776187,16775159,7566195,16775159,16775159,16774388,16775159,16577009,7499373,16513015,6842472,7696753,16711422,16774388,16775159,8946049,16577780,16512244,16512244,8287862,16775159,8551793,16709366,7565167,16512244,16710394,7762546,16776187,1966301,8551538,1966301,1966301,1966301,1966301,1966301,1966301,1966301,2294015,1966301,1966301,1966301,1966301,1966301,1966301,1966301,16571392,16571392,6839645,7104616],[7215538,16775159,16776187,16775159,16775159,16776187,7433580,16579836,9208441,16708595,16711422,8811376,16776187,16708595,16776187,16711422,16579836,16775159,16710394,16512244,7762546,16774388,16578808,16513015,6908265,6842216,16643573,1504118,6842472,16777215,1966301,1966301,1966301,1966301,1966301,1966301,7696753,1966301,1966301,1966301,1966301,1966301,1966301,1966301,16577780,1966301,16775159,16571392,16514043,16644601],[7808943,16775159,16776187,16776187,7499374,16513015,16577780,7630960,16776187,9602951,11784753,16774388,16577009,16708595,16774388,16775159,16775159,16776187,16772846,16577009,9076607,16577009,16775159,16708595,16774388,8221814,16775159,1966301,16774388,1966301,1966301,1966301,1966301,1966301,1966301,2294015,1966301,1966301,1966301,1966301,1966301,1966301,1966301,1966301,16710394,16571392,16571392,16571392,16571392,16578808],[16775159,16776187,16775159,16776187,16511473,8222326,16578808,7630959,16511473,16709366,16773617,16707824,8943491,8946049,16775159,16708595,16709366,16774388,16775159,16775159,16710394,16774388,7628912,16775159,16775159,16578808,1966301,7565167,1966301,1966301,1966301,1966301,1966301,2294015,2294015,1966301,1966301,2294015,1966301,1966301,1966301,1966301,1966301,16315636,16571392,16571392,16571392,16571392,16446451,16381429],[16776187,16775159,16578808,16577780,8287862,16380658,16776187,16709366,16577780,16577009,9077378,16709366,8683378,16775159,16775159,8877698,7434094,16777215,16775159,16775159,16776187,16776187,8812416,9602951,16774388,16775159,1966301,16577780,1966301,1966301,1966301,1966301,1966301,16710394,1966301,1966301,1966301,16709366,2294015,2294015,1966301,1966301,16380401,16571392,16571392,16571392,16571392,16571392,16571392,16644601],[16776187,16775159,16513015,16775159,16512244,16379887,16709366,8288890,16774388,16511473,16776187,16710394,8002248,7500402,16775159,16776187,9271681,7565167,16774388,9010814,16577009,16577009,16578808,7433581,1966301,8810111,1966301,1966301,1966301,1966301,1966301,2294015,2294015,1966301,2294015,2294015,1966301,1966301,1966301,1966301,16381429,16512244,16571392,16571392,16571392,16571392,16571392,16571392,16571392],[16776187,16775159,16512244,16775159,16709366,16579836,7894889,9602180,9340026,7499374,16710394,16513015,7762546,16775159,16776187,8353399,16776187,8036868,16577780,16575467,16775159,7631719,16577780,1966301,1966301,7565167,1966301,1966301,2294015,1966301,16577009,1966301,2294015,16578808,1966301,1966301,1966301,1966301,1966301,16571392,16578808,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16643573,16571392],[16776187,16775159,9077112,16776187,16775159,7565167,8880256,16577780,16513015,16710394,16776187,16710394,16776187,6710630,16775159,8353655,16776187,16710394,16577780,16577009,16577009,16578808,7433581,1966301,8613756,1966301,1966301,1966301,1966301,1966301,2294015,2294015,1966301,2294015,2294015,1966301,1966301,1966301,1966301,16381429,16512244,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16644601],[16774388,16777215,1966301,2294015,2294015,1966301,1966301,1966301,8945021,7630960,2294015,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16777215,16571392,16571392,16571392,16571392,16578808,16571392,16571392,16579836,16571392,16578808,6513258,16579836,16578808,4861858,16776187,5658198,6776679,7499629,8223097,16578808,16578808,7565167,16709366,16579836,16514043,16382457,16711422,16710394,6710886,16709366,0],[16775159,16776187,1966301,1966301,1966301,1966301,2294015,2294015,2294015,8946049,2294015,2294015,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16514043,16776187,16571392,16571392,16776187,16578808,16776187,8419192,7565167,16777215,7565167,16776187,16775159,12566463,16776187,16776187,6710885,16775159,16709366,7827311,8680060,16579836,16382457,7433581,7630704,7168363,16709366,6184542],[16776187,16777215,2294015,16777215,1966301,1966301,1966301,2294015,2294015,16514043,2294015,16571392,2294015,16578808,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16578808,16776187,8880256,16776187,16776187,16578808,16776187,9076607,16775159,7697513,8287862,9601923,16775159,8879485,16773617,16708595,16577780,16775159,16577780,16775159,16578808,16645629,16448250,7565167,7038823],[1446418,1966301,16710394,1966301,16709366,16512244,16578808,2294015,7500402,2294015,7561331,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,7565422,16571392,16571392,16571392,16776187,16776187,16579836,16777215,16777215,16777215,16776187,16579836,8287862,16776187,16774388,16777215,7565422,16710394,7564911,8025461,16775159,16776187,16578808,7564911,8153464,16380658,16776187,16776187,16645629,7564911,7433581],[328965,16776187,7958897,1966301,1966301,16512244,7956598,16774388,16513015,2294015,7566195,16571392,16571392,2294015,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16775159,16777215,16710394,16777215,16776187,16514043,16514043,16513015,7565422,16711422,8223097,12566463,8223097,16645629,16579836,6317414,16710394,16709366,6250335,7500402,7564911,7499374,16513015,16578808,16644601,7566195,11806883,6184542],[328965,16577780,1966301,16709366,1966301,8594127,16710394,16710394,16776187,16579836,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16776187,16571392,16571392,16776187,16578808,16776187,8419192,7565167,16777215,7565167,16776187,16775159,12566463,16776187,16776187,6710885,16775159,16709366,7827311,8680060,16579836,16382457,7433581,7630704,7168363,16709366,6184542],[16777215,16776187,16512244,7826041,7366512,16709366,16577780,16709366,16571392,16571392,16571392,16571392,16571392,16571392,16571392,6184542,16571392,16710394,16578808,8354683,6776934,16777215,6842472,6842472,7500402,16777215,16579836,7170923,16711422,6776679,16776187,16776187,6710886,16777215,16775159,16776187,16513015,16776187,8353655,7565168,16776187,7630704,8223097,16709366,8353655,16776187,16710394,7891571,11082395,7038823],[16776187,16776187,8550006,16709366,16513015,7827311,16381172,16571392,16513015,16710394,16571392,16571392,16571392,16513015,16711422,16571392,6842472,16711422,16571392,16571392,6710885,6711141,16711422,16777215,16777215,16711422,16711422,16711422,16777215,16777215,16777215,16776187,16777215,16645629,16711422,16578808,16776187,16711422,7499375,6842472,16776187,8353655,8222326,8223097,16381429,16776187,7170409,7893104,1906712,7104616],[16777215,16777215,591880,16577780,16577009,9537158,16571392,16571392,16571392,16571392,16571392,16571392,16571392,8354683,16776187,16777215,7631988,16571392,16571392,16776187,16776187,16776187,16776187,16513015,16447222,16578808,16578808,7565167,7499374,16776187,7565167,16644601,6776679,16777215,16777215,16777215,16777215,7565167,16709366,8287862,16776187,16776187,16578808,16578808,16380658,16577780,16776187,9011585,7566195,6184542],[16777215,16777215,131586,1446418,2695457,16571392,16571392,16571392,16571392,16571392,16571392,16571392,16571392,6710886,16571392,7499374,16571392,7630448,7104616,8288890,16776187,16777215,7960681,8222326,8288890,8745584,8483698,16513015,16643573,11211796,16645629,16645629,7168096,6842473,7630960,8809978,16776187,1446418,7630714,6842472,7958897,7958897,2761507,7565167,7565167,16776187,16776187,6250335,6184542,0]]},{"id":"recent","label":"Recent era","txHash":"8tBip5M2TrozhSyepAA3tYXpyKooi5t7b9c64wXjFvfL","blockHeight":194588754,"timestamp":"2026-04-18T21:04:42.229Z","timestampNs":"1776546282229772869","signerId":"sleet.near","pixelCount":2500,"board":[[0,0,0,0,0,0,0,0,0,0,0,65280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,0,0,0,0,0,0,0],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65280,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,65280,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215],[16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,16777215,65280,16777215,16777215,16777215,16777215,16777215,16777215]]}]} diff --git a/src/data/fastnearAiMarkdownFooter.json b/src/data/fastnearAiMarkdownFooter.json new file mode 100644 index 0000000..f48485f --- /dev/null +++ b/src/data/fastnearAiMarkdownFooter.json @@ -0,0 +1,20 @@ +{ + "en": { + "title": "About FastNear", + "bullets": [ + "FastNear handles 10B+ requests per month.", + "FastNear runs 100+ nodes worldwide.", + "One FastNear API key works across RPC and the indexed APIs.", + "Get an API key at [dashboard.fastnear.com](https://dashboard.fastnear.com)." + ] + }, + "ru": { + "title": "О FastNear", + "bullets": [ + "FastNear обрабатывает более 10 млрд запросов в месяц.", + "FastNear управляет более чем 100 нодами по всему миру.", + "Один API-ключ FastNear работает и для RPC, и для индексированных API.", + "Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com)." + ] + } +} diff --git a/src/theme/DocItem/Content/index.js b/src/theme/DocItem/Content/index.js index 6c701bc..30c72da 100644 --- a/src/theme/DocItem/Content/index.js +++ b/src/theme/DocItem/Content/index.js @@ -66,6 +66,7 @@ export default function WrappedDocItemContent(props) { onSelect: async () => { const markdownRoot = contentRef.current?.querySelector('.theme-doc-markdown'); const markdown = buildMarkdownFromDocContent(markdownRoot, { + locale: currentLocale, sourceUrl: typeof window !== 'undefined' ? sanitizePublicUrl(window.location.href) : metadata.permalink, }); @@ -74,7 +75,7 @@ export default function WrappedDocItemContent(props) { }, }, ]; - }, [metadata.permalink, pageActions]); + }, [currentLocale, metadata.permalink, pageActions]); const seoMeta = useMemo(() => { if (!shouldExposeSeo) { diff --git a/src/utils/markdownExport.js b/src/utils/markdownExport.js index 9b8fa11..2b42b29 100644 --- a/src/utils/markdownExport.js +++ b/src/utils/markdownExport.js @@ -1,6 +1,7 @@ import TurndownService from 'turndown'; import { gfm } from 'turndown-plugin-gfm'; import { isNonShareableOperationQueryParam } from './fastnearOperationUrlState'; +import AI_MARKDOWN_FOOTER_COPY from '@site/src/data/fastnearAiMarkdownFooter.json'; const DOC_SKIP_SELECTORS = [ '[data-markdown-skip]', 'button', @@ -172,6 +173,28 @@ function normalizeMarkdown(markdown) { return markdown.replace(/\n{3,}/g, '\n\n').trim(); } +function getFastnearAiFooterCopy(locale = 'en') { + return AI_MARKDOWN_FOOTER_COPY[locale] || AI_MARKDOWN_FOOTER_COPY.en; +} + +function buildFastnearAiFooter(locale = 'en') { + const footerCopy = getFastnearAiFooterCopy(locale); + const sections = [ + `## ${footerCopy.title}`, + '', + ...footerCopy.bullets.map((bullet) => `- ${bullet}`), + ]; + + return `${normalizeMarkdown(sections.join('\n'))}\n`; +} + +function appendFastnearAiFooter(markdown, locale = 'en') { + const normalizedBody = normalizeMarkdown(markdown || ''); + const footer = buildFastnearAiFooter(locale).trim(); + + return `${normalizeMarkdown([normalizedBody, '---', '', footer].filter(Boolean).join('\n'))}\n`; +} + function toAbsoluteUrl(href, baseUrl) { if (!href) { return href; @@ -462,14 +485,14 @@ function formatResponseReference(response, locale = 'en') { return lines.filter(Boolean).join('\n'); } -export function buildMarkdownFromDocContent(rootElement, { sourceUrl } = {}) { +export function buildMarkdownFromDocContent(rootElement, { locale = 'en', sourceUrl } = {}) { if (!rootElement) { return ''; } const clone = prepareDocClone(rootElement, sourceUrl); const markdown = turndownService.turndown(clone.innerHTML); - return `${normalizeMarkdown(markdown)}\n`; + return appendFastnearAiFooter(markdown, locale); } export function buildOperationMarkdown({ @@ -535,5 +558,5 @@ export function buildOperationMarkdown({ sections.push(''); sections.push(formatResponseReference(pageModel.responses?.[0], locale)); - return `${normalizeMarkdown(sections.filter(Boolean).join('\n'))}\n`; + return appendFastnearAiFooter(sections.filter(Boolean).join('\n'), locale); } diff --git a/static/internationalization/index.md b/static/internationalization/index.md index d32bb77..617d3e6 100644 --- a/static/internationalization/index.md +++ b/static/internationalization/index.md @@ -252,3 +252,10 @@ Use this checklist when adding the next language: 9. Add targeted browser checks only if the locale introduces new runtime behavior worth smoke-testing. If those steps are followed, later locales should mostly be editorial work layered onto a stable framework. +--- +## About FastNear + +- FastNear handles 10B+ requests per month. +- FastNear runs 100+ nodes worldwide. +- One FastNear API key works across RPC and the indexed APIs. +- Get an API key at [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/js-loaded-globally/nearjs/0.9.7/cjs/index.cjs b/static/js-loaded-globally/nearjs/0.9.7/cjs/index.cjs deleted file mode 100644 index 52deb37..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/cjs/index.cjs +++ /dev/null @@ -1,25 +0,0 @@ -/* ⋈ 🏃🏻💨 FastNear API - CJS (@fastnear/api version 0.9.7) */ -/* https://www.npmjs.com/package/@fastnear/api/v/0.9.7 */ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default")); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var index_exports = {}; -module.exports = __toCommonJS(index_exports); -__reExport(index_exports, require("./near.js"), module.exports); -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - ...require("./near.js") -}); -//# sourceMappingURL=index.cjs.map diff --git a/static/js-loaded-globally/nearjs/0.9.7/cjs/index.cjs.map b/static/js-loaded-globally/nearjs/0.9.7/cjs/index.cjs.map deleted file mode 100644 index 09878da..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/cjs/index.cjs.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["// See tsup.config.ts for additional banner/footer js\nexport * from \"./near.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA;AAAA;AACA,0BAAc,sBADd;","names":[]} \ No newline at end of file diff --git a/static/js-loaded-globally/nearjs/0.9.7/cjs/index.d.cts b/static/js-loaded-globally/nearjs/0.9.7/cjs/index.d.cts deleted file mode 100644 index 77f036e..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/cjs/index.d.cts +++ /dev/null @@ -1,233 +0,0 @@ -import * as borsh from 'borsh'; - -interface NetworkConfig { - networkId: string; - nodeUrl?: string; - walletUrl?: string; - helperUrl?: string; - explorerUrl?: string; - [key: string]: any; -} -interface TxStatus { - txId: string; - updateTimestamp?: number; - [key: string]: any; -} -type TxHistory = Record; - -declare const MaxBlockDelayMs: number; -interface AccessKeyWithError { - result: { - nonce: number; - permission?: any; - error?: string; - }; -} -interface WalletTxResult { - url?: string; - outcomes?: Array<{ - transaction: { - hash: string; - }; - }>; - rejected?: boolean; - error?: string; -} -interface BlockView { - result: { - header: { - hash: string; - timestamp_nanosec: string; - }; - }; -} -interface LastKnownBlock { - header: { - hash: string; - timestamp_nanosec: string; - }; -} -declare function withBlockId(params: Record, blockId?: string): { - finality: string; -} | { - block_id: string; -}; -declare function sendRpc(method: string, params: Record | any[]): Promise; -declare function afterTxSent(txId: string): void; -declare function sendTxToRpc(signedTxBase64: string, waitUntil: string | undefined, txId: string): Promise; -interface AccessKeyView { - nonce: number; - permission: any; -} -/** - * Generates a mock transaction ID. - * - * This function creates a pseudo-unique transaction ID for testing or - * non-production use. It combines the current timestamp with a - * random component for uniqueness. - * - * **Note:** This is not cryptographically secure and should not be used - * for actual transaction processing. - * - * @returns {string} A mock transaction ID in the format `tx-{timestamp}-{random}` - */ -declare function generateTxId(): string; -declare const accountId: () => string | null | undefined; -declare const publicKey: () => string | null | undefined; -declare const config: (newConfig?: Record) => NetworkConfig; -declare const authStatus: () => string | Record; -declare const getPublicKeyForContract: (opts?: any) => string | null | undefined; -declare const selected: () => { - network: string; - nodeUrl: string | undefined; - walletUrl: string | undefined; - helperUrl: string | undefined; - explorerUrl: string | undefined; - account: string | null | undefined; - contract: string | null | undefined; - publicKey: string | null | undefined; -}; -declare const requestSignIn: ({ contractId }: { - contractId: string; -}) => Promise; -declare const view: ({ contractId, methodName, args, argsBase64, blockId, }: { - contractId: string; - methodName: string; - args?: any; - argsBase64?: string; - blockId?: string; -}) => Promise; -declare const queryAccount: ({ accountId, blockId, }: { - accountId: string; - blockId?: string; -}) => Promise; -declare const queryBlock: ({ blockId }: { - blockId?: string; -}) => Promise; -declare const queryAccessKey: ({ accountId, publicKey, blockId, }: { - accountId: string; - publicKey: string; - blockId?: string; -}) => Promise; -declare const queryTx: ({ txHash, accountId }: { - txHash: string; - accountId: string; -}) => Promise; -declare const localTxHistory: () => TxHistory; -declare const signOut: () => void; -declare const sendTx: ({ receiverId, actions, waitUntil, }: { - receiverId: string; - actions: any[]; - waitUntil?: string; -}) => Promise; -declare const exp: { - utils: {}; - borsh: { - serialize: typeof borsh.serialize; - deserialize: typeof borsh.deserialize; - }; - borshSchema: { - Ed25519Signature: borsh.Schema; - Secp256k1Signature: borsh.Schema; - Signature: borsh.Schema; - Ed25519Data: borsh.Schema; - Secp256k1Data: borsh.Schema; - PublicKey: borsh.Schema; - FunctionCallPermission: borsh.Schema; - FullAccessPermission: borsh.Schema; - AccessKeyPermission: borsh.Schema; - AccessKey: borsh.Schema; - CreateAccount: borsh.Schema; - DeployContract: borsh.Schema; - FunctionCall: borsh.Schema; - Transfer: borsh.Schema; - Stake: borsh.Schema; - AddKey: borsh.Schema; - DeleteKey: borsh.Schema; - DeleteAccount: borsh.Schema; - ClassicAction: borsh.Schema; - DelegateAction: borsh.Schema; - SignedDelegate: borsh.Schema; - Action: borsh.Schema; - Transaction: borsh.Schema; - SignedTransaction: borsh.Schema; - }; -}; -declare const utils: {}; -declare const state: {}; -declare const event: any; -declare const actions: { - functionCall: ({ methodName, gas, deposit, args, argsBase64, }: { - methodName: string; - gas?: string; - deposit?: string; - args?: Record; - argsBase64?: string; - }) => { - type: string; - methodName: string; - args: Record | undefined; - argsBase64: string | undefined; - gas: string | undefined; - deposit: string | undefined; - }; - transfer: (yoctoAmount: string) => { - type: string; - deposit: string; - }; - stakeNEAR: ({ amount, publicKey }: { - amount: string; - publicKey: string; - }) => { - type: string; - stake: string; - publicKey: string; - }; - addFullAccessKey: ({ publicKey }: { - publicKey: string; - }) => { - type: string; - publicKey: string; - accessKey: { - permission: string; - }; - }; - addLimitedAccessKey: ({ publicKey, allowance, accountId, methodNames, }: { - publicKey: string; - allowance: string; - accountId: string; - methodNames: string[]; - }) => { - type: string; - publicKey: string; - accessKey: { - permission: string; - allowance: string; - receiverId: string; - methodNames: string[]; - }; - }; - deleteKey: ({ publicKey }: { - publicKey: string; - }) => { - type: string; - publicKey: string; - }; - deleteAccount: ({ beneficiaryId }: { - beneficiaryId: string; - }) => { - type: string; - beneficiaryId: string; - }; - createAccount: () => { - type: string; - }; - deployContract: ({ codeBase64 }: { - codeBase64: string; - }) => { - type: string; - codeBase64: string; - }; -}; - -export { type AccessKeyView, type AccessKeyWithError, type BlockView, type LastKnownBlock, MaxBlockDelayMs, type WalletTxResult, accountId, actions, afterTxSent, authStatus, config, event, exp, generateTxId, getPublicKeyForContract, localTxHistory, publicKey, queryAccessKey, queryAccount, queryBlock, queryTx, requestSignIn, selected, sendRpc, sendTx, sendTxToRpc, signOut, state, utils, view, withBlockId }; diff --git a/static/js-loaded-globally/nearjs/0.9.7/cjs/near.cjs b/static/js-loaded-globally/nearjs/0.9.7/cjs/near.cjs deleted file mode 100644 index 2fb7463..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/cjs/near.cjs +++ /dev/null @@ -1,553 +0,0 @@ -/* ⋈ 🏃🏻💨 FastNear API - CJS (@fastnear/api version 0.9.7) */ -/* https://www.npmjs.com/package/@fastnear/api/v/0.9.7 */ -"use strict"; -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var near_exports = {}; -__export(near_exports, { - MaxBlockDelayMs: () => MaxBlockDelayMs, - accountId: () => accountId, - actions: () => actions, - afterTxSent: () => afterTxSent, - authStatus: () => authStatus, - config: () => config, - event: () => event, - exp: () => exp, - generateTxId: () => generateTxId, - getPublicKeyForContract: () => getPublicKeyForContract, - localTxHistory: () => localTxHistory, - publicKey: () => publicKey, - queryAccessKey: () => queryAccessKey, - queryAccount: () => queryAccount, - queryBlock: () => queryBlock, - queryTx: () => queryTx, - requestSignIn: () => requestSignIn, - selected: () => selected, - sendRpc: () => sendRpc, - sendTx: () => sendTx, - sendTxToRpc: () => sendTxToRpc, - signOut: () => signOut, - state: () => state, - utils: () => utils, - view: () => view, - withBlockId: () => withBlockId -}); -module.exports = __toCommonJS(near_exports); -var import_big = __toESM(require("big.js"), 1); -var import_utils = require("@fastnear/utils"); -var import_state = require("./state.js"); -var import_state2 = require("./state.js"); -var import_sha2 = require("@noble/hashes/sha2"); -var reExportAllUtils = __toESM(require("@fastnear/utils"), 1); -var stateExports = __toESM(require("./state.js"), 1); -import_big.default.DP = 27; -const MaxBlockDelayMs = 1e3 * 60 * 60 * 6; -function withBlockId(params, blockId) { - if (blockId === "final" || blockId === "optimistic") { - return { ...params, finality: blockId }; - } - return blockId ? { ...params, block_id: blockId } : { ...params, finality: "optimistic" }; -} -__name(withBlockId, "withBlockId"); -async function sendRpc(method, params) { - const config2 = (0, import_state2.getConfig)(); - if (!config2?.nodeUrl) { - throw new Error("fastnear: getConfig() returned invalid config: missing nodeUrl."); - } - const response = await fetch(config2.nodeUrl, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - jsonrpc: "2.0", - id: `fastnear-${Date.now()}`, - method, - params - }) - }); - const result = await response.json(); - if (result.error) { - throw new Error(JSON.stringify(result.error)); - } - return result; -} -__name(sendRpc, "sendRpc"); -function afterTxSent(txId) { - const txHistory = (0, import_state.getTxHistory)(); - sendRpc("tx", { - tx_hash: txHistory[txId]?.txHash, - sender_account_id: txHistory[txId]?.tx?.signerId, - wait_until: "EXECUTED_OPTIMISTIC" - }).then((result) => { - const successValue = result?.result?.status?.SuccessValue; - (0, import_state.updateTxHistory)({ - txId, - status: "Executed", - result, - successValue: successValue ? (0, import_utils.tryParseJson)((0, import_utils.fromBase64)(successValue)) : void 0, - finalState: true - }); - }).catch((error) => { - (0, import_state.updateTxHistory)({ - txId, - status: "ErrorAfterIncluded", - error: (0, import_utils.tryParseJson)(error.message) ?? error.message, - finalState: true - }); - }); -} -__name(afterTxSent, "afterTxSent"); -async function sendTxToRpc(signedTxBase64, waitUntil, txId) { - waitUntil = waitUntil || "INCLUDED"; - try { - const sendTxRes = await sendRpc("send_tx", { - signed_tx_base64: signedTxBase64, - wait_until: waitUntil - }); - (0, import_state.updateTxHistory)({ txId, status: "Included", finalState: false }); - afterTxSent(txId); - return sendTxRes; - } catch (error) { - const errorMessage = error instanceof Error ? error.message : "Unknown error"; - (0, import_state.updateTxHistory)({ - txId, - status: "Error", - error: (0, import_utils.tryParseJson)(errorMessage) ?? errorMessage, - finalState: false - }); - throw new Error(errorMessage); - } -} -__name(sendTxToRpc, "sendTxToRpc"); -function generateTxId() { - const randomPart = crypto.getRandomValues(new Uint32Array(2)).join(""); - return `tx-${Date.now()}-${parseInt(randomPart, 10).toString(36)}`; -} -__name(generateTxId, "generateTxId"); -const accountId = /* @__PURE__ */ __name(() => import_state._state.accountId, "accountId"); -const publicKey = /* @__PURE__ */ __name(() => import_state._state.publicKey, "publicKey"); -const config = /* @__PURE__ */ __name((newConfig) => { - const current = (0, import_state2.getConfig)(); - if (newConfig) { - if (newConfig.networkId && current.networkId !== newConfig.networkId) { - (0, import_state2.setConfig)(newConfig.networkId); - (0, import_state.update)({ accountId: null, privateKey: null, lastWalletId: null }); - (0, import_utils.lsSet)("block", null); - (0, import_state2.resetTxHistory)(); - } - (0, import_state2.setConfig)({ ...(0, import_state2.getConfig)(), ...newConfig }); - } - return (0, import_state2.getConfig)(); -}, "config"); -const authStatus = /* @__PURE__ */ __name(() => { - if (!import_state._state.accountId) { - return "SignedOut"; - } - return "SignedIn"; -}, "authStatus"); -const getPublicKeyForContract = /* @__PURE__ */ __name((opts) => { - return publicKey(); -}, "getPublicKeyForContract"); -const selected = /* @__PURE__ */ __name(() => { - const network = (0, import_state2.getConfig)().networkId; - const nodeUrl = (0, import_state2.getConfig)().nodeUrl; - const walletUrl = (0, import_state2.getConfig)().walletUrl; - const helperUrl = (0, import_state2.getConfig)().helperUrl; - const explorerUrl = (0, import_state2.getConfig)().explorerUrl; - const account = accountId(); - const contract = import_state._state.accessKeyContractId; - const publicKey2 = getPublicKeyForContract(); - return { - network, - nodeUrl, - walletUrl, - helperUrl, - explorerUrl, - account, - contract, - publicKey: publicKey2 - }; -}, "selected"); -const requestSignIn = /* @__PURE__ */ __name(async ({ contractId }) => { - const privateKey = (0, import_utils.privateKeyFromRandom)(); - (0, import_state.update)({ accessKeyContractId: contractId, accountId: null, privateKey }); - const pubKey = (0, import_utils.publicKeyFromPrivate)(privateKey); - const result = await import_state._adapter.signIn({ - networkId: (0, import_state2.getConfig)().networkId, - contractId, - publicKey: pubKey - }); - if (result.error) { - throw new Error(`Wallet error: ${result.error}`); - } - if (result.url) { - if (typeof window !== "undefined") { - setTimeout(() => { - window.location.href = result.url; - }, 100); - } - } else if (result.accountId) { - (0, import_state.update)({ accountId: result.accountId }); - } -}, "requestSignIn"); -const view = /* @__PURE__ */ __name(async ({ - contractId, - methodName, - args, - argsBase64, - blockId -}) => { - const encodedArgs = argsBase64 || (args ? (0, import_utils.toBase64)(JSON.stringify(args)) : ""); - const queryResult = await sendRpc( - "query", - withBlockId( - { - request_type: "call_function", - account_id: contractId, - method_name: methodName, - args_base64: encodedArgs - }, - blockId - ) - ); - return (0, import_utils.parseJsonFromBytes)(queryResult.result.result); -}, "view"); -const queryAccount = /* @__PURE__ */ __name(async ({ - accountId: accountId2, - blockId -}) => { - return sendRpc( - "query", - withBlockId({ request_type: "view_account", account_id: accountId2 }, blockId) - ); -}, "queryAccount"); -const queryBlock = /* @__PURE__ */ __name(async ({ blockId }) => { - return sendRpc("block", withBlockId({}, blockId)); -}, "queryBlock"); -const queryAccessKey = /* @__PURE__ */ __name(async ({ - accountId: accountId2, - publicKey: publicKey2, - blockId -}) => { - return sendRpc( - "query", - withBlockId( - { request_type: "view_access_key", account_id: accountId2, public_key: publicKey2 }, - blockId - ) - ); -}, "queryAccessKey"); -const queryTx = /* @__PURE__ */ __name(async ({ txHash, accountId: accountId2 }) => { - return sendRpc("tx", [txHash, accountId2]); -}, "queryTx"); -const localTxHistory = /* @__PURE__ */ __name(() => { - return (0, import_state.getTxHistory)(); -}, "localTxHistory"); -const signOut = /* @__PURE__ */ __name(() => { - (0, import_state.update)({ accountId: null, privateKey: null, contractId: null }); - (0, import_state2.setConfig)(import_state.NETWORKS[import_state.DEFAULT_NETWORK_ID]); -}, "signOut"); -const sendTx = /* @__PURE__ */ __name(async ({ - receiverId, - actions: actions2, - waitUntil -}) => { - const signerId = import_state._state.accountId; - if (!signerId) throw new Error("Must sign in"); - const publicKey2 = import_state._state.publicKey ?? ""; - const privKey = import_state._state.privateKey; - const txId = generateTxId(); - if (!privKey || receiverId !== import_state._state.accessKeyContractId || !(0, import_utils.canSignWithLAK)(actions2)) { - const jsonTx = { signerId, receiverId, actions: actions2 }; - (0, import_state.updateTxHistory)({ status: "Pending", txId, tx: jsonTx, finalState: false }); - const url = new URL(typeof window !== "undefined" ? window.location.href : ""); - url.searchParams.set("txIds", txId); - const existingParams = new URLSearchParams(window.location.search); - existingParams.forEach((value, key) => { - if (!url.searchParams.has(key)) { - url.searchParams.set(key, value); - } - }); - url.searchParams.delete("errorCode"); - url.searchParams.delete("errorMessage"); - try { - const result = await import_state._adapter.sendTransactions({ - transactions: [jsonTx], - callbackUrl: url.toString() - }); - if (result.url) { - if (typeof window !== "undefined") { - setTimeout(() => { - window.location.href = result.url; - }, 100); - } - } else if (result.outcomes?.length) { - result.outcomes.forEach( - (r) => (0, import_state.updateTxHistory)({ - txId, - status: "Executed", - result: r, - txHash: r.transaction.hash, - finalState: true - }) - ); - } else if (result.rejected) { - (0, import_state.updateTxHistory)({ txId, status: "RejectedByUser", finalState: true }); - } else if (result.error) { - (0, import_state.updateTxHistory)({ - txId, - status: "Error", - error: (0, import_utils.tryParseJson)(result.error), - finalState: true - }); - } - return result; - } catch (err) { - console.error("fastnear: error sending tx using adapter:", err); - (0, import_state.updateTxHistory)({ - txId, - status: "Error", - error: (0, import_utils.tryParseJson)(err.message), - finalState: true - }); - return Promise.reject(err); - } - } - let nonce = (0, import_utils.lsGet)("nonce"); - if (nonce == null) { - const accessKey = await queryAccessKey({ accountId: signerId, publicKey: publicKey2 }); - if (accessKey.result.error) { - throw new Error(`Access key error: ${accessKey.result.error} when attempting to get nonce for ${signerId} for public key ${publicKey2}`); - } - nonce = accessKey.result.nonce; - (0, import_utils.lsSet)("nonce", nonce); - } - let lastKnownBlock = (0, import_utils.lsGet)("block"); - if (!lastKnownBlock || parseFloat(lastKnownBlock.header.timestamp_nanosec) / 1e6 + MaxBlockDelayMs < Date.now()) { - const latestBlock = await queryBlock({ blockId: "final" }); - lastKnownBlock = { - header: { - hash: latestBlock.result.header.hash, - timestamp_nanosec: latestBlock.result.header.timestamp_nanosec - } - }; - (0, import_utils.lsSet)("block", lastKnownBlock); - } - nonce += 1; - (0, import_utils.lsSet)("nonce", nonce); - const blockHash = lastKnownBlock.header.hash; - const plainTransactionObj = { - signerId, - publicKey: publicKey2, - nonce, - receiverId, - blockHash, - actions: actions2 - }; - const txBytes = (0, import_utils.serializeTransaction)(plainTransactionObj); - const txHashBytes = (0, import_sha2.sha256)(txBytes); - const txHash58 = (0, import_utils.toBase58)(txHashBytes); - const signatureBase58 = (0, import_utils.signHash)(txHashBytes, privKey, { returnBase58: true }); - const signedTransactionBytes = (0, import_utils.serializeSignedTransaction)(plainTransactionObj, signatureBase58); - const signedTxBase64 = (0, import_utils.bytesToBase64)(signedTransactionBytes); - (0, import_state.updateTxHistory)({ - status: "Pending", - txId, - tx: plainTransactionObj, - signature: signatureBase58, - signedTxBase64, - txHash: txHash58, - finalState: false - }); - try { - return await sendTxToRpc(signedTxBase64, waitUntil, txId); - } catch (error) { - console.error("Error Sending Transaction:", error, plainTransactionObj, signedTxBase64); - } -}, "sendTx"); -const exp = { - utils: {}, - // we will map this in a moment, giving keys, for IDE hints - borsh: reExportAllUtils.exp.borsh, - borshSchema: reExportAllUtils.exp.borshSchema.getBorshSchema() -}; -for (const key in reExportAllUtils) { - exp.utils[key] = reExportAllUtils[key]; -} -const utils = exp.utils; -const state = {}; -for (const key in stateExports) { - state[key] = stateExports[key]; -} -const event = state["events"]; -delete state["events"]; -try { - if (typeof window !== "undefined") { - const url = new URL(window.location.href); - const accId = url.searchParams.get("account_id"); - const pubKey = url.searchParams.get("public_key"); - const errCode = url.searchParams.get("errorCode"); - const errMsg = url.searchParams.get("errorMessage"); - const decodedErrMsg = errMsg ? decodeURIComponent(errMsg) : null; - const txHashes = url.searchParams.get("transactionHashes"); - const txIds = url.searchParams.get("txIds"); - if (errCode || errMsg) { - console.warn(new Error(`Wallet raises: -code: ${errCode} -message: ${decodedErrMsg}`)); - } - if (accId && pubKey) { - if (pubKey === import_state._state.publicKey) { - (0, import_state.update)({ accountId: accId }); - } else { - if (authStatus() === "SignedIn") { - console.warn("Public key mismatch from wallet redirect", pubKey, import_state._state.publicKey); - } - url.searchParams.delete("public_key"); - } - } - if (txHashes || txIds) { - const hashArr = txHashes ? txHashes.split(",") : []; - const idArr = txIds ? txIds.split(",") : []; - if (idArr.length > hashArr.length) { - idArr.forEach((id) => { - (0, import_state.updateTxHistory)({ txId: id, status: "RejectedByUser", finalState: true }); - }); - } else if (idArr.length === hashArr.length) { - idArr.forEach((id, i) => { - (0, import_state.updateTxHistory)({ - txId: id, - status: "PendingGotTxHash", - txHash: hashArr[i], - finalState: false - }); - afterTxSent(id); - }); - } else { - console.error(new Error("Transaction hash mismatch from wallet redirect"), idArr, hashArr); - } - } - url.searchParams.delete("txIds"); - if (authStatus() === "SignedOut") { - url.searchParams.delete("errorCode"); - url.searchParams.delete("errorMessage"); - } - } -} catch (e) { - console.error("Error handling wallet redirect:", e); -} -const actions = { - functionCall: /* @__PURE__ */ __name(({ - methodName, - gas, - deposit, - args, - argsBase64 - }) => ({ - type: "FunctionCall", - methodName, - args, - argsBase64, - gas, - deposit - }), "functionCall"), - transfer: /* @__PURE__ */ __name((yoctoAmount) => ({ - type: "Transfer", - deposit: yoctoAmount - }), "transfer"), - stakeNEAR: /* @__PURE__ */ __name(({ amount, publicKey: publicKey2 }) => ({ - type: "Stake", - stake: amount, - publicKey: publicKey2 - }), "stakeNEAR"), - addFullAccessKey: /* @__PURE__ */ __name(({ publicKey: publicKey2 }) => ({ - type: "AddKey", - publicKey: publicKey2, - accessKey: { permission: "FullAccess" } - }), "addFullAccessKey"), - addLimitedAccessKey: /* @__PURE__ */ __name(({ - publicKey: publicKey2, - allowance, - accountId: accountId2, - methodNames - }) => ({ - type: "AddKey", - publicKey: publicKey2, - accessKey: { - permission: "FunctionCall", - allowance, - receiverId: accountId2, - methodNames - } - }), "addLimitedAccessKey"), - deleteKey: /* @__PURE__ */ __name(({ publicKey: publicKey2 }) => ({ - type: "DeleteKey", - publicKey: publicKey2 - }), "deleteKey"), - deleteAccount: /* @__PURE__ */ __name(({ beneficiaryId }) => ({ - type: "DeleteAccount", - beneficiaryId - }), "deleteAccount"), - createAccount: /* @__PURE__ */ __name(() => ({ - type: "CreateAccount" - }), "createAccount"), - deployContract: /* @__PURE__ */ __name(({ codeBase64 }) => ({ - type: "DeployContract", - codeBase64 - }), "deployContract") -}; -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - MaxBlockDelayMs, - accountId, - actions, - afterTxSent, - authStatus, - config, - event, - exp, - generateTxId, - getPublicKeyForContract, - localTxHistory, - publicKey, - queryAccessKey, - queryAccount, - queryBlock, - queryTx, - requestSignIn, - selected, - sendRpc, - sendTx, - sendTxToRpc, - signOut, - state, - utils, - view, - withBlockId -}); -//# sourceMappingURL=near.cjs.map diff --git a/static/js-loaded-globally/nearjs/0.9.7/cjs/near.cjs.map b/static/js-loaded-globally/nearjs/0.9.7/cjs/near.cjs.map deleted file mode 100644 index 72b8090..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/cjs/near.cjs.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["../../src/near.ts"],"sourcesContent":["import Big from \"big.js\";\nimport {\n lsSet,\n lsGet,\n tryParseJson,\n fromBase64,\n toBase64,\n canSignWithLAK,\n toBase58,\n parseJsonFromBytes,\n signHash,\n publicKeyFromPrivate,\n privateKeyFromRandom,\n serializeTransaction,\n serializeSignedTransaction, bytesToBase64, PlainTransaction,\n} from \"@fastnear/utils\";\n\nimport {\n _adapter,\n _state,\n DEFAULT_NETWORK_ID,\n NETWORKS,\n getTxHistory,\n update,\n updateTxHistory,\n} from \"./state.js\";\n\nimport {\n getConfig,\n setConfig,\n resetTxHistory,\n} from \"./state.js\";\n\nimport { sha256 } from \"@noble/hashes/sha2\";\nimport * as reExportAllUtils from \"@fastnear/utils\";\nimport * as stateExports from \"./state.js\";\n\nBig.DP = 27;\nexport const MaxBlockDelayMs = 1000 * 60 * 60 * 6; // 6 hours\n\nexport interface AccessKeyWithError {\n result: {\n nonce: number;\n permission?: any;\n error?: string;\n }\n}\n\nexport interface WalletTxResult {\n url?: string;\n outcomes?: Array<{ transaction: { hash: string } }>;\n rejected?: boolean;\n error?: string;\n}\n\nexport interface BlockView {\n result: {\n header: {\n hash: string;\n timestamp_nanosec: string;\n }\n }\n}\n\n// The structure it's saved to in storage\nexport interface LastKnownBlock {\n header: {\n hash: string;\n timestamp_nanosec: string;\n }\n}\n\nexport function withBlockId(params: Record, blockId?: string) {\n if (blockId === \"final\" || blockId === \"optimistic\") {\n return { ...params, finality: blockId };\n }\n return blockId ? { ...params, block_id: blockId } : { ...params, finality: \"optimistic\" };\n}\n\nexport async function sendRpc(method: string, params: Record | any[]) {\n const config = getConfig();\n if (!config?.nodeUrl) {\n throw new Error(\"fastnear: getConfig() returned invalid config: missing nodeUrl.\");\n }\n const response = await fetch(config.nodeUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: `fastnear-${Date.now()}`,\n method,\n params,\n }),\n });\n const result = await response.json();\n if (result.error) {\n throw new Error(JSON.stringify(result.error));\n }\n return result;\n}\n\nexport function afterTxSent(txId: string) {\n const txHistory = getTxHistory();\n sendRpc(\"tx\", {\n tx_hash: txHistory[txId]?.txHash,\n sender_account_id: txHistory[txId]?.tx?.signerId,\n wait_until: \"EXECUTED_OPTIMISTIC\",\n })\n .then( result => {\n const successValue = result?.result?.status?.SuccessValue;\n updateTxHistory({\n txId,\n status: \"Executed\",\n result,\n successValue: successValue ? tryParseJson(fromBase64(successValue)) : undefined,\n finalState: true,\n });\n })\n .catch((error) => {\n updateTxHistory({\n txId,\n status: \"ErrorAfterIncluded\",\n error: tryParseJson(error.message) ?? error.message,\n finalState: true,\n });\n });\n}\n\nexport async function sendTxToRpc(signedTxBase64: string, waitUntil: string | undefined, txId: string) {\n // default to \"INCLUDED\"\n // see options: https://docs.near.org/api/rpc/transactions#tx-status-result\n waitUntil = waitUntil || \"INCLUDED\";\n\n try {\n const sendTxRes = await sendRpc(\"send_tx\", {\n signed_tx_base64: signedTxBase64,\n wait_until: waitUntil,\n });\n\n updateTxHistory({ txId, status: \"Included\", finalState: false });\n afterTxSent(txId);\n\n return sendTxRes;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n updateTxHistory({\n txId,\n status: \"Error\",\n error: tryParseJson(errorMessage) ?? errorMessage,\n finalState: false,\n });\n throw new Error(errorMessage);\n }\n}\n\nexport interface AccessKeyView {\n nonce: number;\n permission: any;\n}\n\n/**\n * Generates a mock transaction ID.\n *\n * This function creates a pseudo-unique transaction ID for testing or\n * non-production use. It combines the current timestamp with a\n * random component for uniqueness.\n *\n * **Note:** This is not cryptographically secure and should not be used\n * for actual transaction processing.\n *\n * @returns {string} A mock transaction ID in the format `tx-{timestamp}-{random}`\n */\nexport function generateTxId(): string {\n const randomPart = crypto.getRandomValues(new Uint32Array(2)).join(\"\");\n return `tx-${Date.now()}-${parseInt(randomPart, 10).toString(36)}`;\n}\n\nexport const accountId = () => _state.accountId;\nexport const publicKey = () => _state.publicKey;\n\nexport const config = (newConfig?: Record) => {\n const current = getConfig();\n if (newConfig) {\n if (newConfig.networkId && current.networkId !== newConfig.networkId) {\n setConfig(newConfig.networkId);\n update({ accountId: null, privateKey: null, lastWalletId: null });\n lsSet(\"block\", null);\n resetTxHistory();\n }\n setConfig({ ...getConfig(), ...newConfig });\n }\n return getConfig();\n};\n\nexport const authStatus = (): string | Record => {\n if (!_state.accountId) {\n return \"SignedOut\";\n }\n return \"SignedIn\";\n};\n\n// this is an intentional stub\n// and it's probably partially done, to help ease future features\n// for now we'll assume each web end user has one keypair in storage\n// for every contract they wish to interact with\n// later, it may be prudent to hold multiple, but until then this function\n// just returns the access key as if it were among others in the array.\n// we're pretending like we really thought about which access key we're returning\n// based on the opts argument. this allows us to fill this logic in later.\nexport const getPublicKeyForContract = (opts?: any) => {\n return publicKey();\n}\n\n// returns details on the selected:\n// network, wallet, and explorer details as well as\n// sending account, contract, and selected public key\nexport const selected = () => {\n const network = getConfig().networkId;\n const nodeUrl = getConfig().nodeUrl;\n const walletUrl = getConfig().walletUrl;\n const helperUrl = getConfig().helperUrl;\n const explorerUrl = getConfig().explorerUrl;\n\n const account = accountId();\n const contract = _state.accessKeyContractId;\n const publicKey = getPublicKeyForContract();\n\n return {\n network,\n nodeUrl,\n walletUrl,\n helperUrl,\n explorerUrl,\n account,\n contract,\n publicKey\n }\n}\n\nexport const requestSignIn = async ({ contractId }: { contractId: string }) => {\n const privateKey = privateKeyFromRandom();\n update({ accessKeyContractId: contractId, accountId: null, privateKey });\n const pubKey = publicKeyFromPrivate(privateKey);\n\n const result = await _adapter.signIn({\n networkId: getConfig().networkId,\n contractId,\n publicKey: pubKey,\n });\n\n if (result.error) {\n throw new Error(`Wallet error: ${result.error}`);\n }\n if (result.url) {\n if (typeof window !== \"undefined\") {\n setTimeout(() => {\n window.location.href = result.url;\n }, 100);\n }\n } else if (result.accountId) {\n update({ accountId: result.accountId });\n }\n};\n\nexport const view = async ({\n contractId,\n methodName,\n args,\n argsBase64,\n blockId,\n }: {\n contractId: string;\n methodName: string;\n args?: any;\n argsBase64?: string;\n blockId?: string;\n}) => {\n const encodedArgs = argsBase64 || (args ? toBase64(JSON.stringify(args)) : \"\");\n const queryResult = await sendRpc(\n \"query\",\n withBlockId(\n {\n request_type: \"call_function\",\n account_id: contractId,\n method_name: methodName,\n args_base64: encodedArgs,\n },\n blockId\n )\n );\n\n return parseJsonFromBytes(queryResult.result.result);\n};\n\nexport const queryAccount = async ({\n accountId,\n blockId,\n }: {\n accountId: string;\n blockId?: string;\n}) => {\n return sendRpc(\n \"query\",\n withBlockId({ request_type: \"view_account\", account_id: accountId }, blockId)\n );\n};\n\nexport const queryBlock = async ({ blockId }: { blockId?: string }): Promise => {\n return sendRpc(\"block\", withBlockId({}, blockId));\n};\n\nexport const queryAccessKey = async ({\n accountId,\n publicKey,\n blockId,\n }: {\n accountId: string;\n publicKey: string;\n blockId?: string;\n}): Promise => {\n return sendRpc(\n \"query\",\n withBlockId(\n { request_type: \"view_access_key\", account_id: accountId, public_key: publicKey },\n blockId\n )\n );\n};\n\nexport const queryTx = async ({ txHash, accountId }: { txHash: string; accountId: string }) => {\n return sendRpc(\"tx\", [txHash, accountId]);\n};\n\nexport const localTxHistory = () => {\n return getTxHistory();\n};\n\nexport const signOut = () => {\n update({ accountId: null, privateKey: null, contractId: null });\n setConfig(NETWORKS[DEFAULT_NETWORK_ID]);\n};\n\nexport const sendTx = async ({\n receiverId,\n actions,\n waitUntil,\n }: {\n receiverId: string;\n actions: any[];\n waitUntil?: string;\n}) => {\n const signerId = _state.accountId;\n if (!signerId) throw new Error(\"Must sign in\");\n\n const publicKey = _state.publicKey ?? \"\";\n const privKey = _state.privateKey;\n // this generates a mock transaction ID so we can keep track of each tx\n const txId = generateTxId();\n\n if (!privKey || receiverId !== _state.accessKeyContractId || !canSignWithLAK(actions)) {\n const jsonTx = { signerId, receiverId, actions };\n updateTxHistory({ status: \"Pending\", txId, tx: jsonTx, finalState: false });\n\n const url = new URL(typeof window !== \"undefined\" ? window.location.href : \"\");\n url.searchParams.set(\"txIds\", txId);\n\n // preserve existing url params\n const existingParams = new URLSearchParams(window.location.search);\n existingParams.forEach((value, key) => {\n if (!url.searchParams.has(key)) {\n url.searchParams.set(key, value);\n }\n });\n\n // we're wanting to preserve URL params that we send in\n // but make sure we're not feeding back error params\n // from a previous failure\n\n url.searchParams.delete(\"errorCode\");\n url.searchParams.delete(\"errorMessage\");\n\n try {\n const result: WalletTxResult = await _adapter.sendTransactions({\n transactions: [jsonTx],\n callbackUrl: url.toString(),\n });\n\n if (result.url) {\n if (typeof window !== \"undefined\") {\n setTimeout(() => {\n window.location.href = result.url!;\n }, 100);\n }\n } else if (result.outcomes?.length) {\n result.outcomes.forEach((r) =>\n updateTxHistory({\n txId,\n status: \"Executed\",\n result: r,\n txHash: r.transaction.hash,\n finalState: true,\n })\n );\n } else if (result.rejected) {\n updateTxHistory({ txId, status: \"RejectedByUser\", finalState: true });\n } else if (result.error) {\n updateTxHistory({\n txId,\n status: \"Error\",\n error: tryParseJson(result.error),\n finalState: true,\n });\n }\n\n return result;\n } catch (err) {\n console.error('fastnear: error sending tx using adapter:', err)\n updateTxHistory({\n txId,\n status: \"Error\",\n error: tryParseJson((err as Error).message),\n finalState: true,\n });\n\n return Promise.reject(err);\n }\n }\n\n let nonce = lsGet(\"nonce\") as number | null;\n if (nonce == null) {\n const accessKey = await queryAccessKey({ accountId: signerId, publicKey: publicKey });\n if (accessKey.result.error) {\n throw new Error(`Access key error: ${accessKey.result.error} when attempting to get nonce for ${signerId} for public key ${publicKey}`);\n }\n nonce = accessKey.result.nonce;\n lsSet(\"nonce\", nonce);\n }\n\n let lastKnownBlock = lsGet(\"block\") as LastKnownBlock | null;\n if (\n !lastKnownBlock ||\n parseFloat(lastKnownBlock.header.timestamp_nanosec) / 1e6 + MaxBlockDelayMs < Date.now()\n ) {\n const latestBlock = await queryBlock({ blockId: \"final\" });\n lastKnownBlock = {\n header: {\n hash: latestBlock.result.header.hash,\n timestamp_nanosec: latestBlock.result.header.timestamp_nanosec,\n },\n };\n lsSet(\"block\", lastKnownBlock);\n }\n\n nonce += 1;\n lsSet(\"nonce\", nonce);\n\n const blockHash = lastKnownBlock.header.hash;\n\n const plainTransactionObj: PlainTransaction = {\n signerId,\n publicKey,\n nonce,\n receiverId,\n blockHash,\n actions,\n };\n\n const txBytes = serializeTransaction(plainTransactionObj);\n const txHashBytes = sha256(txBytes);\n const txHash58 = toBase58(txHashBytes);\n\n const signatureBase58 = signHash(txHashBytes, privKey, { returnBase58: true });\n const signedTransactionBytes = serializeSignedTransaction(plainTransactionObj, signatureBase58);\n const signedTxBase64 = bytesToBase64(signedTransactionBytes);\n\n updateTxHistory({\n status: \"Pending\",\n txId,\n tx: plainTransactionObj,\n signature: signatureBase58,\n signedTxBase64,\n txHash: txHash58,\n finalState: false,\n });\n\n try {\n return await sendTxToRpc(signedTxBase64, waitUntil, txId);\n } catch (error) {\n console.error(\"Error Sending Transaction:\", error, plainTransactionObj, signedTxBase64);\n }\n};\n\n// exports\nexport const exp = {\n utils: {}, // we will map this in a moment, giving keys, for IDE hints\n borsh: reExportAllUtils.exp.borsh,\n borshSchema: reExportAllUtils.exp.borshSchema.getBorshSchema(),\n};\n\nfor (const key in reExportAllUtils) {\n exp.utils[key] = reExportAllUtils[key];\n}\n\n// devx\nexport const utils = exp.utils;\n\nexport const state = {}\n\nfor (const key in stateExports) {\n state[key] = stateExports[key];\n}\n\n// devx\n\nexport const event = state['events'];\ndelete state['events'];\n\n// Wallet redirect handling\ntry {\n if (typeof window !== \"undefined\") {\n const url = new URL(window.location.href);\n const accId = url.searchParams.get(\"account_id\");\n const pubKey = url.searchParams.get(\"public_key\");\n const errCode = url.searchParams.get(\"errorCode\");\n const errMsg = url.searchParams.get(\"errorMessage\");\n const decodedErrMsg = errMsg ? decodeURIComponent(errMsg) : null;\n\n const txHashes = url.searchParams.get(\"transactionHashes\");\n const txIds = url.searchParams.get(\"txIds\");\n\n if (errCode || errMsg) {\n console.warn(new Error(`Wallet raises:\\ncode: ${errCode}\\nmessage: ${decodedErrMsg}`));\n }\n\n if (accId && pubKey) {\n if (pubKey === _state.publicKey) {\n update({ accountId: accId });\n } else {\n // it's possible the end user has a URL param that's old. we'll remove the public_key param\n // if logged out, no need to throw warning\n if (authStatus() === \"SignedIn\") {\n console.warn(\"Public key mismatch from wallet redirect\", pubKey, _state.publicKey);\n }\n url.searchParams.delete(\"public_key\");\n }\n }\n\n if (txHashes || txIds) {\n const hashArr = txHashes ? txHashes.split(\",\") : [];\n const idArr = txIds ? txIds.split(\",\") : [];\n if (idArr.length > hashArr.length) {\n idArr.forEach((id) => {\n updateTxHistory({ txId: id, status: \"RejectedByUser\", finalState: true });\n });\n } else if (idArr.length === hashArr.length) {\n idArr.forEach((id, i) => {\n updateTxHistory({\n txId: id,\n status: \"PendingGotTxHash\",\n txHash: hashArr[i],\n finalState: false,\n });\n afterTxSent(id);\n });\n } else {\n console.error(new Error(\"Transaction hash mismatch from wallet redirect\"), idArr, hashArr);\n }\n }\n\n // we can consider removing these, but want to be careful because\n // it can be helpful for a dev to have a URL they can debug with\n // we won't want to remove information\n\n // pretty sure txIds can go, especially if you can tell it's been more than 5 minutes or something\n // public_key sometimes confuses it, so this might only be needed when adding a new access key\n // and perhaps once we've confirmed that the transaction hashes are getting saved to storage\n // (not sure about that section of code) then we can get rid of the transactionHashes, too\n\n url.searchParams.delete(\"txIds\");\n if (authStatus() === \"SignedOut\") {\n url.searchParams.delete(\"errorCode\");\n url.searchParams.delete(\"errorMessage\");\n }\n // ^ we've decided these ones make sense to keep\n\n // I'd like to keep this for posterity. for a bit.\n // url.searchParams.delete(\"account_id\");\n // url.searchParams.delete(\"public_key\");\n\n // url.searchParams.delete(\"all_keys\");\n // url.searchParams.delete(\"transactionHashes\");\n // window.history.replaceState({}, \"\", url.toString());\n }\n} catch (e) {\n console.error(\"Error handling wallet redirect:\", e);\n}\n\n// action helpers\nexport const actions = {\n functionCall: ({\n methodName,\n gas,\n deposit,\n args,\n argsBase64,\n }: {\n methodName: string;\n gas?: string;\n deposit?: string;\n args?: Record;\n argsBase64?: string;\n }) => ({\n type: \"FunctionCall\",\n methodName,\n args,\n argsBase64,\n gas,\n deposit,\n }),\n\n transfer: (yoctoAmount: string) => ({\n type: \"Transfer\",\n deposit: yoctoAmount,\n }),\n\n stakeNEAR: ({amount, publicKey}: { amount: string; publicKey: string }) => ({\n type: \"Stake\",\n stake: amount,\n publicKey,\n }),\n\n addFullAccessKey: ({publicKey}: { publicKey: string }) => ({\n type: \"AddKey\",\n publicKey: publicKey,\n accessKey: {permission: \"FullAccess\"},\n }),\n\n addLimitedAccessKey: ({\n publicKey,\n allowance,\n accountId,\n methodNames,\n }: {\n publicKey: string;\n allowance: string;\n accountId: string;\n methodNames: string[];\n }) => ({\n type: \"AddKey\",\n publicKey: publicKey,\n accessKey: {\n permission: \"FunctionCall\",\n allowance,\n receiverId: accountId,\n methodNames,\n },\n }),\n\n deleteKey: ({publicKey}: { publicKey: string }) => ({\n type: \"DeleteKey\",\n publicKey,\n }),\n\n deleteAccount: ({beneficiaryId}: { beneficiaryId: string }) => ({\n type: \"DeleteAccount\",\n beneficiaryId,\n }),\n\n createAccount: () => ({\n type: \"CreateAccount\",\n }),\n\n deployContract: ({codeBase64}: { codeBase64: string }) => ({\n type: \"DeployContract\",\n codeBase64,\n }),\n};\n"],"mappings":"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","names":["import_state","Big","config","publicKey","accountId","actions"]} \ No newline at end of file diff --git a/static/js-loaded-globally/nearjs/0.9.7/cjs/state.cjs b/static/js-loaded-globally/nearjs/0.9.7/cjs/state.cjs deleted file mode 100644 index 7b81417..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/cjs/state.cjs +++ /dev/null @@ -1,207 +0,0 @@ -/* ⋈ 🏃🏻💨 FastNear API - CJS (@fastnear/api version 0.9.7) */ -/* https://www.npmjs.com/package/@fastnear/api/v/0.9.7 */ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var state_exports = {}; -__export(state_exports, { - DEFAULT_NETWORK_ID: () => DEFAULT_NETWORK_ID, - NETWORKS: () => NETWORKS, - WIDGET_URL: () => WIDGET_URL, - _adapter: () => _adapter, - _config: () => _config, - _state: () => _state, - _txHistory: () => _txHistory, - _unbroadcastedEvents: () => _unbroadcastedEvents, - events: () => events, - getConfig: () => getConfig, - getTxHistory: () => getTxHistory, - getWalletAdapterState: () => getWalletAdapterState, - onAdapterStateUpdate: () => onAdapterStateUpdate, - resetTxHistory: () => resetTxHistory, - setConfig: () => setConfig, - update: () => update, - updateTxHistory: () => updateTxHistory -}); -module.exports = __toCommonJS(state_exports); -var import_utils = require("@fastnear/utils"); -var import_wallet_adapter = require("@fastnear/wallet-adapter"); -const WIDGET_URL = "https://js.cdn.fastnear.com"; -const DEFAULT_NETWORK_ID = "mainnet"; -const NETWORKS = { - testnet: { - networkId: "testnet", - nodeUrl: "https://rpc.testnet.fastnear.com/" - }, - mainnet: { - networkId: "mainnet", - nodeUrl: "https://rpc.mainnet.fastnear.com/" - } -}; -let _config = (0, import_utils.lsGet)("config") || { - ...NETWORKS[DEFAULT_NETWORK_ID] -}; -let _state = (0, import_utils.lsGet)("state") || {}; -const onAdapterStateUpdate = /* @__PURE__ */ __name((state) => { - console.log("Adapter state update:", state); - const { accountId, lastWalletId, privateKey } = state; - update({ - accountId: accountId || void 0, - lastWalletId: lastWalletId || void 0, - ...privateKey ? { privateKey } : {} - }); -}, "onAdapterStateUpdate"); -const getWalletAdapterState = /* @__PURE__ */ __name(() => { - return { - publicKey: _state.publicKey, - accountId: _state.accountId, - lastWalletId: _state.lastWalletId, - networkId: _config.networkId - }; -}, "getWalletAdapterState"); -let _adapter = new import_wallet_adapter.WalletAdapter({ - onStateUpdate: onAdapterStateUpdate, - lastState: getWalletAdapterState(), - widgetUrl: WIDGET_URL -}); -try { - _state.publicKey = _state.privateKey ? (0, import_utils.publicKeyFromPrivate)(_state.privateKey) : null; -} catch (e) { - console.error("Error parsing private key:", e); - _state.privateKey = null; - (0, import_utils.lsSet)("nonce", null); -} -let _txHistory = (0, import_utils.lsGet)("txHistory") || {}; -const _unbroadcastedEvents = { - account: [], - tx: [] -}; -const events = { - _eventListeners: { - account: /* @__PURE__ */ new Set(), - tx: /* @__PURE__ */ new Set() - }, - notifyAccountListeners: /* @__PURE__ */ __name((accountId) => { - if (events._eventListeners.account.size === 0) { - _unbroadcastedEvents.account.push(accountId); - return; - } - events._eventListeners.account.forEach((callback) => { - try { - callback(accountId); - } catch (e) { - console.error(e); - } - }); - }, "notifyAccountListeners"), - notifyTxListeners: /* @__PURE__ */ __name((tx) => { - if (events._eventListeners.tx.size === 0) { - _unbroadcastedEvents.tx.push(tx); - return; - } - events._eventListeners.tx.forEach((callback) => { - try { - callback(tx); - } catch (e) { - console.error(e); - } - }); - }, "notifyTxListeners"), - onAccount: /* @__PURE__ */ __name((callback) => { - events._eventListeners.account.add(callback); - if (_unbroadcastedEvents.account.length > 0) { - const accountEvent = _unbroadcastedEvents.account; - _unbroadcastedEvents.account = []; - accountEvent.forEach(events.notifyAccountListeners); - } - }, "onAccount"), - onTx: /* @__PURE__ */ __name((callback) => { - events._eventListeners.tx.add(callback); - if (_unbroadcastedEvents.tx.length > 0) { - const txEvent = _unbroadcastedEvents.tx; - _unbroadcastedEvents.tx = []; - txEvent.forEach(events.notifyTxListeners); - } - }, "onTx") -}; -const update = /* @__PURE__ */ __name((newState) => { - const oldState = _state; - _state = { ..._state, ...newState }; - (0, import_utils.lsSet)("state", { - accountId: _state.accountId, - privateKey: _state.privateKey, - lastWalletId: _state.lastWalletId, - accessKeyContractId: _state.accessKeyContractId - }); - if (newState.hasOwnProperty("privateKey") && newState.privateKey !== oldState.privateKey) { - _state.publicKey = newState.privateKey ? (0, import_utils.publicKeyFromPrivate)(newState.privateKey) : null; - (0, import_utils.lsSet)("nonce", null); - } - if (newState.accountId !== oldState.accountId) { - events.notifyAccountListeners(newState.accountId); - } - if (newState.hasOwnProperty("lastWalletId") && newState.lastWalletId !== oldState.lastWalletId || newState.hasOwnProperty("accountId") && newState.accountId !== oldState.accountId || newState.hasOwnProperty("privateKey") && newState.privateKey !== oldState.privateKey) { - _adapter.setState(getWalletAdapterState()); - } -}, "update"); -const updateTxHistory = /* @__PURE__ */ __name((txStatus) => { - const txId = txStatus.txId; - _txHistory[txId] = { - ..._txHistory[txId] || {}, - ...txStatus, - updateTimestamp: Date.now() - }; - (0, import_utils.lsSet)("txHistory", _txHistory); - events.notifyTxListeners(_txHistory[txId]); -}, "updateTxHistory"); -const getConfig = /* @__PURE__ */ __name(() => { - return _config; -}, "getConfig"); -const getTxHistory = /* @__PURE__ */ __name(() => { - return _txHistory; -}, "getTxHistory"); -const setConfig = /* @__PURE__ */ __name((newConf) => { - _config = { ...NETWORKS[newConf.networkId], ...newConf }; - (0, import_utils.lsSet)("config", _config); -}, "setConfig"); -const resetTxHistory = /* @__PURE__ */ __name(() => { - _txHistory = {}; - (0, import_utils.lsSet)("txHistory", _txHistory); -}, "resetTxHistory"); -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - DEFAULT_NETWORK_ID, - NETWORKS, - WIDGET_URL, - _adapter, - _config, - _state, - _txHistory, - _unbroadcastedEvents, - events, - getConfig, - getTxHistory, - getWalletAdapterState, - onAdapterStateUpdate, - resetTxHistory, - setConfig, - update, - updateTxHistory -}); -//# sourceMappingURL=state.cjs.map diff --git a/static/js-loaded-globally/nearjs/0.9.7/cjs/state.cjs.map b/static/js-loaded-globally/nearjs/0.9.7/cjs/state.cjs.map deleted file mode 100644 index 4f7cfdb..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/cjs/state.cjs.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["../../src/state.ts"],"sourcesContent":["import {\n lsSet,\n lsGet,\n publicKeyFromPrivate,\n} from \"@fastnear/utils\";\nimport {WalletAdapter} from \"@fastnear/wallet-adapter\";\n\nexport const WIDGET_URL = \"https://js.cdn.fastnear.com\";\n\nexport const DEFAULT_NETWORK_ID = \"mainnet\";\nexport const NETWORKS = {\n testnet: {\n networkId: \"testnet\",\n nodeUrl: \"https://rpc.testnet.fastnear.com/\",\n },\n mainnet: {\n networkId: \"mainnet\",\n nodeUrl: \"https://rpc.mainnet.fastnear.com/\",\n },\n};\n\nexport interface NetworkConfig {\n networkId: string;\n nodeUrl?: string;\n walletUrl?: string;\n helperUrl?: string;\n explorerUrl?: string;\n\n [key: string]: any;\n}\n\nexport interface AppState {\n accountId?: string | null;\n privateKey?: string | null;\n lastWalletId?: string | null;\n publicKey?: string | null;\n accessKeyContractId?: string | null;\n\n [key: string]: any;\n}\n\nexport interface TxStatus {\n txId: string;\n updateTimestamp?: number;\n\n [key: string]: any;\n}\n\nexport type TxHistory = Record;\n\nexport interface EventListeners {\n account: Set<(accountId: string) => void>;\n tx: Set<(tx: TxStatus) => void>;\n}\n\nexport interface UnbroadcastedEvents {\n account: string[];\n tx: TxStatus[];\n}\n\nexport interface WalletAdapterState {\n publicKey?: string | null;\n privateKey?: string | null;\n accountId?: string | null;\n lastWalletId?: string | null;\n networkId: string;\n}\n\n\n// Load config from localStorage or default to the network's config\nexport let _config: NetworkConfig = lsGet(\"config\") || {\n ...NETWORKS[DEFAULT_NETWORK_ID]\n};\n\n// Load application state from localStorage\nexport let _state: AppState = lsGet(\"state\") || {};\n\n// Triggered by the wallet adapter\nexport const onAdapterStateUpdate = (state: WalletAdapterState) => {\n console.log(\"Adapter state update:\", state);\n const { accountId, lastWalletId, privateKey } = state;\n update({\n accountId: accountId || undefined,\n lastWalletId: lastWalletId || undefined,\n ...(privateKey ? { privateKey } : {}),\n });\n}\n\nexport const getWalletAdapterState = (): WalletAdapterState => {\n return {\n publicKey: _state.publicKey,\n accountId: _state.accountId,\n lastWalletId: _state.lastWalletId,\n networkId: _config.networkId,\n };\n}\n\n// We can create an adapter instance here\nexport let _adapter = new WalletAdapter({\n onStateUpdate: onAdapterStateUpdate,\n lastState: getWalletAdapterState(),\n widgetUrl: WIDGET_URL,\n});\n\n// Attempt to set publicKey if we have a privateKey\ntry {\n _state.publicKey = _state.privateKey\n ? publicKeyFromPrivate(_state.privateKey)\n : null;\n} catch (e) {\n console.error(\"Error parsing private key:\", e);\n _state.privateKey = null;\n lsSet(\"nonce\", null);\n}\n\n// Transaction history\nexport let _txHistory: TxHistory = lsGet(\"txHistory\") || {};\n\n\nexport const _unbroadcastedEvents: UnbroadcastedEvents = {\n account: [],\n tx: [],\n};\n\n// events / listeners\nexport const events = {\n _eventListeners: {\n account: new Set(),\n tx: new Set(),\n },\n\n notifyAccountListeners: (accountId: string) => {\n if (events._eventListeners.account.size === 0) {\n _unbroadcastedEvents.account.push(accountId);\n return;\n }\n events._eventListeners.account.forEach((callback: any) => {\n try {\n callback(accountId);\n } catch (e) {\n console.error(e);\n }\n });\n },\n\n notifyTxListeners: (tx: TxStatus) => {\n if (events._eventListeners.tx.size === 0) {\n _unbroadcastedEvents.tx.push(tx);\n return;\n }\n events._eventListeners.tx.forEach((callback: any) => {\n try {\n callback(tx);\n } catch (e) {\n console.error(e);\n }\n });\n },\n\n onAccount: (callback: (accountId: string) => void) => {\n events._eventListeners.account.add(callback);\n if (_unbroadcastedEvents.account.length > 0) {\n const accountEvent = _unbroadcastedEvents.account;\n _unbroadcastedEvents.account = [];\n accountEvent.forEach(events.notifyAccountListeners);\n }\n },\n\n onTx: (callback: (tx: TxStatus) => void): void => {\n events._eventListeners.tx.add(callback);\n if (_unbroadcastedEvents.tx.length > 0) {\n const txEvent = _unbroadcastedEvents.tx;\n _unbroadcastedEvents.tx = [];\n txEvent.forEach(events.notifyTxListeners);\n }\n }\n}\n\n// Mutators\n// @todo: in favor of limiting when out of alpha\n// but haven't given it enough thought ~ mike\nexport const update = (newState: Partial) => {\n const oldState = _state;\n _state = {..._state, ...newState};\n\n lsSet(\"state\", {\n accountId: _state.accountId,\n privateKey: _state.privateKey,\n lastWalletId: _state.lastWalletId,\n accessKeyContractId: _state.accessKeyContractId,\n });\n\n if (\n newState.hasOwnProperty(\"privateKey\") &&\n newState.privateKey !== oldState.privateKey\n ) {\n _state.publicKey = newState.privateKey\n ? publicKeyFromPrivate(newState.privateKey as string)\n : null;\n lsSet(\"nonce\", null);\n }\n\n if (newState.accountId !== oldState.accountId) {\n events.notifyAccountListeners(newState.accountId as string);\n }\n\n if (\n (newState.hasOwnProperty(\"lastWalletId\") &&\n newState.lastWalletId !== oldState.lastWalletId) ||\n (newState.hasOwnProperty(\"accountId\") &&\n newState.accountId !== oldState.accountId) ||\n (newState.hasOwnProperty(\"privateKey\") &&\n newState.privateKey !== oldState.privateKey)\n ) {\n _adapter.setState(getWalletAdapterState());\n }\n}\n\nexport const updateTxHistory = (txStatus: TxStatus) => {\n const txId = txStatus.txId;\n _txHistory[txId] = {\n ...(_txHistory[txId] || {}),\n ...txStatus,\n updateTimestamp: Date.now(),\n };\n lsSet(\"txHistory\", _txHistory);\n events.notifyTxListeners(_txHistory[txId]);\n}\n\nexport const getConfig = (): NetworkConfig => {\n return _config;\n}\n\nexport const getTxHistory = (): TxHistory => {\n return _txHistory;\n}\n\n// Exposed \"write\" functions\nexport const setConfig = (newConf: NetworkConfig): void => {\n _config = { ...NETWORKS[newConf.networkId], ...newConf };\n lsSet(\"config\", _config);\n}\n\nexport const resetTxHistory = (): void => {\n _txHistory = {};\n lsSet(\"txHistory\", _txHistory);\n}\n"],"mappings":"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","names":[]} \ No newline at end of file diff --git a/static/js-loaded-globally/nearjs/0.9.7/esm/index.d.ts b/static/js-loaded-globally/nearjs/0.9.7/esm/index.d.ts deleted file mode 100644 index 77f036e..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/esm/index.d.ts +++ /dev/null @@ -1,233 +0,0 @@ -import * as borsh from 'borsh'; - -interface NetworkConfig { - networkId: string; - nodeUrl?: string; - walletUrl?: string; - helperUrl?: string; - explorerUrl?: string; - [key: string]: any; -} -interface TxStatus { - txId: string; - updateTimestamp?: number; - [key: string]: any; -} -type TxHistory = Record; - -declare const MaxBlockDelayMs: number; -interface AccessKeyWithError { - result: { - nonce: number; - permission?: any; - error?: string; - }; -} -interface WalletTxResult { - url?: string; - outcomes?: Array<{ - transaction: { - hash: string; - }; - }>; - rejected?: boolean; - error?: string; -} -interface BlockView { - result: { - header: { - hash: string; - timestamp_nanosec: string; - }; - }; -} -interface LastKnownBlock { - header: { - hash: string; - timestamp_nanosec: string; - }; -} -declare function withBlockId(params: Record, blockId?: string): { - finality: string; -} | { - block_id: string; -}; -declare function sendRpc(method: string, params: Record | any[]): Promise; -declare function afterTxSent(txId: string): void; -declare function sendTxToRpc(signedTxBase64: string, waitUntil: string | undefined, txId: string): Promise; -interface AccessKeyView { - nonce: number; - permission: any; -} -/** - * Generates a mock transaction ID. - * - * This function creates a pseudo-unique transaction ID for testing or - * non-production use. It combines the current timestamp with a - * random component for uniqueness. - * - * **Note:** This is not cryptographically secure and should not be used - * for actual transaction processing. - * - * @returns {string} A mock transaction ID in the format `tx-{timestamp}-{random}` - */ -declare function generateTxId(): string; -declare const accountId: () => string | null | undefined; -declare const publicKey: () => string | null | undefined; -declare const config: (newConfig?: Record) => NetworkConfig; -declare const authStatus: () => string | Record; -declare const getPublicKeyForContract: (opts?: any) => string | null | undefined; -declare const selected: () => { - network: string; - nodeUrl: string | undefined; - walletUrl: string | undefined; - helperUrl: string | undefined; - explorerUrl: string | undefined; - account: string | null | undefined; - contract: string | null | undefined; - publicKey: string | null | undefined; -}; -declare const requestSignIn: ({ contractId }: { - contractId: string; -}) => Promise; -declare const view: ({ contractId, methodName, args, argsBase64, blockId, }: { - contractId: string; - methodName: string; - args?: any; - argsBase64?: string; - blockId?: string; -}) => Promise; -declare const queryAccount: ({ accountId, blockId, }: { - accountId: string; - blockId?: string; -}) => Promise; -declare const queryBlock: ({ blockId }: { - blockId?: string; -}) => Promise; -declare const queryAccessKey: ({ accountId, publicKey, blockId, }: { - accountId: string; - publicKey: string; - blockId?: string; -}) => Promise; -declare const queryTx: ({ txHash, accountId }: { - txHash: string; - accountId: string; -}) => Promise; -declare const localTxHistory: () => TxHistory; -declare const signOut: () => void; -declare const sendTx: ({ receiverId, actions, waitUntil, }: { - receiverId: string; - actions: any[]; - waitUntil?: string; -}) => Promise; -declare const exp: { - utils: {}; - borsh: { - serialize: typeof borsh.serialize; - deserialize: typeof borsh.deserialize; - }; - borshSchema: { - Ed25519Signature: borsh.Schema; - Secp256k1Signature: borsh.Schema; - Signature: borsh.Schema; - Ed25519Data: borsh.Schema; - Secp256k1Data: borsh.Schema; - PublicKey: borsh.Schema; - FunctionCallPermission: borsh.Schema; - FullAccessPermission: borsh.Schema; - AccessKeyPermission: borsh.Schema; - AccessKey: borsh.Schema; - CreateAccount: borsh.Schema; - DeployContract: borsh.Schema; - FunctionCall: borsh.Schema; - Transfer: borsh.Schema; - Stake: borsh.Schema; - AddKey: borsh.Schema; - DeleteKey: borsh.Schema; - DeleteAccount: borsh.Schema; - ClassicAction: borsh.Schema; - DelegateAction: borsh.Schema; - SignedDelegate: borsh.Schema; - Action: borsh.Schema; - Transaction: borsh.Schema; - SignedTransaction: borsh.Schema; - }; -}; -declare const utils: {}; -declare const state: {}; -declare const event: any; -declare const actions: { - functionCall: ({ methodName, gas, deposit, args, argsBase64, }: { - methodName: string; - gas?: string; - deposit?: string; - args?: Record; - argsBase64?: string; - }) => { - type: string; - methodName: string; - args: Record | undefined; - argsBase64: string | undefined; - gas: string | undefined; - deposit: string | undefined; - }; - transfer: (yoctoAmount: string) => { - type: string; - deposit: string; - }; - stakeNEAR: ({ amount, publicKey }: { - amount: string; - publicKey: string; - }) => { - type: string; - stake: string; - publicKey: string; - }; - addFullAccessKey: ({ publicKey }: { - publicKey: string; - }) => { - type: string; - publicKey: string; - accessKey: { - permission: string; - }; - }; - addLimitedAccessKey: ({ publicKey, allowance, accountId, methodNames, }: { - publicKey: string; - allowance: string; - accountId: string; - methodNames: string[]; - }) => { - type: string; - publicKey: string; - accessKey: { - permission: string; - allowance: string; - receiverId: string; - methodNames: string[]; - }; - }; - deleteKey: ({ publicKey }: { - publicKey: string; - }) => { - type: string; - publicKey: string; - }; - deleteAccount: ({ beneficiaryId }: { - beneficiaryId: string; - }) => { - type: string; - beneficiaryId: string; - }; - createAccount: () => { - type: string; - }; - deployContract: ({ codeBase64 }: { - codeBase64: string; - }) => { - type: string; - codeBase64: string; - }; -}; - -export { type AccessKeyView, type AccessKeyWithError, type BlockView, type LastKnownBlock, MaxBlockDelayMs, type WalletTxResult, accountId, actions, afterTxSent, authStatus, config, event, exp, generateTxId, getPublicKeyForContract, localTxHistory, publicKey, queryAccessKey, queryAccount, queryBlock, queryTx, requestSignIn, selected, sendRpc, sendTx, sendTxToRpc, signOut, state, utils, view, withBlockId }; diff --git a/static/js-loaded-globally/nearjs/0.9.7/esm/index.js b/static/js-loaded-globally/nearjs/0.9.7/esm/index.js deleted file mode 100644 index d84199b..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/esm/index.js +++ /dev/null @@ -1,4 +0,0 @@ -/* ⋈ 🏃🏻💨 FastNear API - ESM (@fastnear/api version 0.9.7) */ -/* https://www.npmjs.com/package/@fastnear/api/v/0.9.7 */ -export * from "./near.js"; -//# sourceMappingURL=index.js.map diff --git a/static/js-loaded-globally/nearjs/0.9.7/esm/index.js.map b/static/js-loaded-globally/nearjs/0.9.7/esm/index.js.map deleted file mode 100644 index 6162288..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/esm/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["// See tsup.config.ts for additional banner/footer js\nexport * from \"./near.js\";\n"],"mappings":";;AACA,cAAc;","names":[]} \ No newline at end of file diff --git a/static/js-loaded-globally/nearjs/0.9.7/esm/near.js b/static/js-loaded-globally/nearjs/0.9.7/esm/near.js deleted file mode 100644 index 7c793d4..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/esm/near.js +++ /dev/null @@ -1,522 +0,0 @@ -/* ⋈ 🏃🏻💨 FastNear API - ESM (@fastnear/api version 0.9.7) */ -/* https://www.npmjs.com/package/@fastnear/api/v/0.9.7 */ -var __defProp = Object.defineProperty; -var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); -import Big from "big.js"; -import { - lsSet, - lsGet, - tryParseJson, - fromBase64, - toBase64, - canSignWithLAK, - toBase58, - parseJsonFromBytes, - signHash, - publicKeyFromPrivate, - privateKeyFromRandom, - serializeTransaction, - serializeSignedTransaction, - bytesToBase64 -} from "@fastnear/utils"; -import { - _adapter, - _state, - DEFAULT_NETWORK_ID, - NETWORKS, - getTxHistory, - update, - updateTxHistory -} from "./state.js"; -import { - getConfig, - setConfig, - resetTxHistory -} from "./state.js"; -import { sha256 } from "@noble/hashes/sha2"; -import * as reExportAllUtils from "@fastnear/utils"; -import * as stateExports from "./state.js"; -Big.DP = 27; -const MaxBlockDelayMs = 1e3 * 60 * 60 * 6; -function withBlockId(params, blockId) { - if (blockId === "final" || blockId === "optimistic") { - return { ...params, finality: blockId }; - } - return blockId ? { ...params, block_id: blockId } : { ...params, finality: "optimistic" }; -} -__name(withBlockId, "withBlockId"); -async function sendRpc(method, params) { - const config2 = getConfig(); - if (!config2?.nodeUrl) { - throw new Error("fastnear: getConfig() returned invalid config: missing nodeUrl."); - } - const response = await fetch(config2.nodeUrl, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - jsonrpc: "2.0", - id: `fastnear-${Date.now()}`, - method, - params - }) - }); - const result = await response.json(); - if (result.error) { - throw new Error(JSON.stringify(result.error)); - } - return result; -} -__name(sendRpc, "sendRpc"); -function afterTxSent(txId) { - const txHistory = getTxHistory(); - sendRpc("tx", { - tx_hash: txHistory[txId]?.txHash, - sender_account_id: txHistory[txId]?.tx?.signerId, - wait_until: "EXECUTED_OPTIMISTIC" - }).then((result) => { - const successValue = result?.result?.status?.SuccessValue; - updateTxHistory({ - txId, - status: "Executed", - result, - successValue: successValue ? tryParseJson(fromBase64(successValue)) : void 0, - finalState: true - }); - }).catch((error) => { - updateTxHistory({ - txId, - status: "ErrorAfterIncluded", - error: tryParseJson(error.message) ?? error.message, - finalState: true - }); - }); -} -__name(afterTxSent, "afterTxSent"); -async function sendTxToRpc(signedTxBase64, waitUntil, txId) { - waitUntil = waitUntil || "INCLUDED"; - try { - const sendTxRes = await sendRpc("send_tx", { - signed_tx_base64: signedTxBase64, - wait_until: waitUntil - }); - updateTxHistory({ txId, status: "Included", finalState: false }); - afterTxSent(txId); - return sendTxRes; - } catch (error) { - const errorMessage = error instanceof Error ? error.message : "Unknown error"; - updateTxHistory({ - txId, - status: "Error", - error: tryParseJson(errorMessage) ?? errorMessage, - finalState: false - }); - throw new Error(errorMessage); - } -} -__name(sendTxToRpc, "sendTxToRpc"); -function generateTxId() { - const randomPart = crypto.getRandomValues(new Uint32Array(2)).join(""); - return `tx-${Date.now()}-${parseInt(randomPart, 10).toString(36)}`; -} -__name(generateTxId, "generateTxId"); -const accountId = /* @__PURE__ */ __name(() => _state.accountId, "accountId"); -const publicKey = /* @__PURE__ */ __name(() => _state.publicKey, "publicKey"); -const config = /* @__PURE__ */ __name((newConfig) => { - const current = getConfig(); - if (newConfig) { - if (newConfig.networkId && current.networkId !== newConfig.networkId) { - setConfig(newConfig.networkId); - update({ accountId: null, privateKey: null, lastWalletId: null }); - lsSet("block", null); - resetTxHistory(); - } - setConfig({ ...getConfig(), ...newConfig }); - } - return getConfig(); -}, "config"); -const authStatus = /* @__PURE__ */ __name(() => { - if (!_state.accountId) { - return "SignedOut"; - } - return "SignedIn"; -}, "authStatus"); -const getPublicKeyForContract = /* @__PURE__ */ __name((opts) => { - return publicKey(); -}, "getPublicKeyForContract"); -const selected = /* @__PURE__ */ __name(() => { - const network = getConfig().networkId; - const nodeUrl = getConfig().nodeUrl; - const walletUrl = getConfig().walletUrl; - const helperUrl = getConfig().helperUrl; - const explorerUrl = getConfig().explorerUrl; - const account = accountId(); - const contract = _state.accessKeyContractId; - const publicKey2 = getPublicKeyForContract(); - return { - network, - nodeUrl, - walletUrl, - helperUrl, - explorerUrl, - account, - contract, - publicKey: publicKey2 - }; -}, "selected"); -const requestSignIn = /* @__PURE__ */ __name(async ({ contractId }) => { - const privateKey = privateKeyFromRandom(); - update({ accessKeyContractId: contractId, accountId: null, privateKey }); - const pubKey = publicKeyFromPrivate(privateKey); - const result = await _adapter.signIn({ - networkId: getConfig().networkId, - contractId, - publicKey: pubKey - }); - if (result.error) { - throw new Error(`Wallet error: ${result.error}`); - } - if (result.url) { - if (typeof window !== "undefined") { - setTimeout(() => { - window.location.href = result.url; - }, 100); - } - } else if (result.accountId) { - update({ accountId: result.accountId }); - } -}, "requestSignIn"); -const view = /* @__PURE__ */ __name(async ({ - contractId, - methodName, - args, - argsBase64, - blockId -}) => { - const encodedArgs = argsBase64 || (args ? toBase64(JSON.stringify(args)) : ""); - const queryResult = await sendRpc( - "query", - withBlockId( - { - request_type: "call_function", - account_id: contractId, - method_name: methodName, - args_base64: encodedArgs - }, - blockId - ) - ); - return parseJsonFromBytes(queryResult.result.result); -}, "view"); -const queryAccount = /* @__PURE__ */ __name(async ({ - accountId: accountId2, - blockId -}) => { - return sendRpc( - "query", - withBlockId({ request_type: "view_account", account_id: accountId2 }, blockId) - ); -}, "queryAccount"); -const queryBlock = /* @__PURE__ */ __name(async ({ blockId }) => { - return sendRpc("block", withBlockId({}, blockId)); -}, "queryBlock"); -const queryAccessKey = /* @__PURE__ */ __name(async ({ - accountId: accountId2, - publicKey: publicKey2, - blockId -}) => { - return sendRpc( - "query", - withBlockId( - { request_type: "view_access_key", account_id: accountId2, public_key: publicKey2 }, - blockId - ) - ); -}, "queryAccessKey"); -const queryTx = /* @__PURE__ */ __name(async ({ txHash, accountId: accountId2 }) => { - return sendRpc("tx", [txHash, accountId2]); -}, "queryTx"); -const localTxHistory = /* @__PURE__ */ __name(() => { - return getTxHistory(); -}, "localTxHistory"); -const signOut = /* @__PURE__ */ __name(() => { - update({ accountId: null, privateKey: null, contractId: null }); - setConfig(NETWORKS[DEFAULT_NETWORK_ID]); -}, "signOut"); -const sendTx = /* @__PURE__ */ __name(async ({ - receiverId, - actions: actions2, - waitUntil -}) => { - const signerId = _state.accountId; - if (!signerId) throw new Error("Must sign in"); - const publicKey2 = _state.publicKey ?? ""; - const privKey = _state.privateKey; - const txId = generateTxId(); - if (!privKey || receiverId !== _state.accessKeyContractId || !canSignWithLAK(actions2)) { - const jsonTx = { signerId, receiverId, actions: actions2 }; - updateTxHistory({ status: "Pending", txId, tx: jsonTx, finalState: false }); - const url = new URL(typeof window !== "undefined" ? window.location.href : ""); - url.searchParams.set("txIds", txId); - const existingParams = new URLSearchParams(window.location.search); - existingParams.forEach((value, key) => { - if (!url.searchParams.has(key)) { - url.searchParams.set(key, value); - } - }); - url.searchParams.delete("errorCode"); - url.searchParams.delete("errorMessage"); - try { - const result = await _adapter.sendTransactions({ - transactions: [jsonTx], - callbackUrl: url.toString() - }); - if (result.url) { - if (typeof window !== "undefined") { - setTimeout(() => { - window.location.href = result.url; - }, 100); - } - } else if (result.outcomes?.length) { - result.outcomes.forEach( - (r) => updateTxHistory({ - txId, - status: "Executed", - result: r, - txHash: r.transaction.hash, - finalState: true - }) - ); - } else if (result.rejected) { - updateTxHistory({ txId, status: "RejectedByUser", finalState: true }); - } else if (result.error) { - updateTxHistory({ - txId, - status: "Error", - error: tryParseJson(result.error), - finalState: true - }); - } - return result; - } catch (err) { - console.error("fastnear: error sending tx using adapter:", err); - updateTxHistory({ - txId, - status: "Error", - error: tryParseJson(err.message), - finalState: true - }); - return Promise.reject(err); - } - } - let nonce = lsGet("nonce"); - if (nonce == null) { - const accessKey = await queryAccessKey({ accountId: signerId, publicKey: publicKey2 }); - if (accessKey.result.error) { - throw new Error(`Access key error: ${accessKey.result.error} when attempting to get nonce for ${signerId} for public key ${publicKey2}`); - } - nonce = accessKey.result.nonce; - lsSet("nonce", nonce); - } - let lastKnownBlock = lsGet("block"); - if (!lastKnownBlock || parseFloat(lastKnownBlock.header.timestamp_nanosec) / 1e6 + MaxBlockDelayMs < Date.now()) { - const latestBlock = await queryBlock({ blockId: "final" }); - lastKnownBlock = { - header: { - hash: latestBlock.result.header.hash, - timestamp_nanosec: latestBlock.result.header.timestamp_nanosec - } - }; - lsSet("block", lastKnownBlock); - } - nonce += 1; - lsSet("nonce", nonce); - const blockHash = lastKnownBlock.header.hash; - const plainTransactionObj = { - signerId, - publicKey: publicKey2, - nonce, - receiverId, - blockHash, - actions: actions2 - }; - const txBytes = serializeTransaction(plainTransactionObj); - const txHashBytes = sha256(txBytes); - const txHash58 = toBase58(txHashBytes); - const signatureBase58 = signHash(txHashBytes, privKey, { returnBase58: true }); - const signedTransactionBytes = serializeSignedTransaction(plainTransactionObj, signatureBase58); - const signedTxBase64 = bytesToBase64(signedTransactionBytes); - updateTxHistory({ - status: "Pending", - txId, - tx: plainTransactionObj, - signature: signatureBase58, - signedTxBase64, - txHash: txHash58, - finalState: false - }); - try { - return await sendTxToRpc(signedTxBase64, waitUntil, txId); - } catch (error) { - console.error("Error Sending Transaction:", error, plainTransactionObj, signedTxBase64); - } -}, "sendTx"); -const exp = { - utils: {}, - // we will map this in a moment, giving keys, for IDE hints - borsh: reExportAllUtils.exp.borsh, - borshSchema: reExportAllUtils.exp.borshSchema.getBorshSchema() -}; -for (const key in reExportAllUtils) { - exp.utils[key] = reExportAllUtils[key]; -} -const utils = exp.utils; -const state = {}; -for (const key in stateExports) { - state[key] = stateExports[key]; -} -const event = state["events"]; -delete state["events"]; -try { - if (typeof window !== "undefined") { - const url = new URL(window.location.href); - const accId = url.searchParams.get("account_id"); - const pubKey = url.searchParams.get("public_key"); - const errCode = url.searchParams.get("errorCode"); - const errMsg = url.searchParams.get("errorMessage"); - const decodedErrMsg = errMsg ? decodeURIComponent(errMsg) : null; - const txHashes = url.searchParams.get("transactionHashes"); - const txIds = url.searchParams.get("txIds"); - if (errCode || errMsg) { - console.warn(new Error(`Wallet raises: -code: ${errCode} -message: ${decodedErrMsg}`)); - } - if (accId && pubKey) { - if (pubKey === _state.publicKey) { - update({ accountId: accId }); - } else { - if (authStatus() === "SignedIn") { - console.warn("Public key mismatch from wallet redirect", pubKey, _state.publicKey); - } - url.searchParams.delete("public_key"); - } - } - if (txHashes || txIds) { - const hashArr = txHashes ? txHashes.split(",") : []; - const idArr = txIds ? txIds.split(",") : []; - if (idArr.length > hashArr.length) { - idArr.forEach((id) => { - updateTxHistory({ txId: id, status: "RejectedByUser", finalState: true }); - }); - } else if (idArr.length === hashArr.length) { - idArr.forEach((id, i) => { - updateTxHistory({ - txId: id, - status: "PendingGotTxHash", - txHash: hashArr[i], - finalState: false - }); - afterTxSent(id); - }); - } else { - console.error(new Error("Transaction hash mismatch from wallet redirect"), idArr, hashArr); - } - } - url.searchParams.delete("txIds"); - if (authStatus() === "SignedOut") { - url.searchParams.delete("errorCode"); - url.searchParams.delete("errorMessage"); - } - } -} catch (e) { - console.error("Error handling wallet redirect:", e); -} -const actions = { - functionCall: /* @__PURE__ */ __name(({ - methodName, - gas, - deposit, - args, - argsBase64 - }) => ({ - type: "FunctionCall", - methodName, - args, - argsBase64, - gas, - deposit - }), "functionCall"), - transfer: /* @__PURE__ */ __name((yoctoAmount) => ({ - type: "Transfer", - deposit: yoctoAmount - }), "transfer"), - stakeNEAR: /* @__PURE__ */ __name(({ amount, publicKey: publicKey2 }) => ({ - type: "Stake", - stake: amount, - publicKey: publicKey2 - }), "stakeNEAR"), - addFullAccessKey: /* @__PURE__ */ __name(({ publicKey: publicKey2 }) => ({ - type: "AddKey", - publicKey: publicKey2, - accessKey: { permission: "FullAccess" } - }), "addFullAccessKey"), - addLimitedAccessKey: /* @__PURE__ */ __name(({ - publicKey: publicKey2, - allowance, - accountId: accountId2, - methodNames - }) => ({ - type: "AddKey", - publicKey: publicKey2, - accessKey: { - permission: "FunctionCall", - allowance, - receiverId: accountId2, - methodNames - } - }), "addLimitedAccessKey"), - deleteKey: /* @__PURE__ */ __name(({ publicKey: publicKey2 }) => ({ - type: "DeleteKey", - publicKey: publicKey2 - }), "deleteKey"), - deleteAccount: /* @__PURE__ */ __name(({ beneficiaryId }) => ({ - type: "DeleteAccount", - beneficiaryId - }), "deleteAccount"), - createAccount: /* @__PURE__ */ __name(() => ({ - type: "CreateAccount" - }), "createAccount"), - deployContract: /* @__PURE__ */ __name(({ codeBase64 }) => ({ - type: "DeployContract", - codeBase64 - }), "deployContract") -}; -export { - MaxBlockDelayMs, - accountId, - actions, - afterTxSent, - authStatus, - config, - event, - exp, - generateTxId, - getPublicKeyForContract, - localTxHistory, - publicKey, - queryAccessKey, - queryAccount, - queryBlock, - queryTx, - requestSignIn, - selected, - sendRpc, - sendTx, - sendTxToRpc, - signOut, - state, - utils, - view, - withBlockId -}; -//# sourceMappingURL=near.js.map diff --git a/static/js-loaded-globally/nearjs/0.9.7/esm/near.js.map b/static/js-loaded-globally/nearjs/0.9.7/esm/near.js.map deleted file mode 100644 index 6105d62..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/esm/near.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["../../src/near.ts"],"sourcesContent":["import Big from \"big.js\";\nimport {\n lsSet,\n lsGet,\n tryParseJson,\n fromBase64,\n toBase64,\n canSignWithLAK,\n toBase58,\n parseJsonFromBytes,\n signHash,\n publicKeyFromPrivate,\n privateKeyFromRandom,\n serializeTransaction,\n serializeSignedTransaction, bytesToBase64, PlainTransaction,\n} from \"@fastnear/utils\";\n\nimport {\n _adapter,\n _state,\n DEFAULT_NETWORK_ID,\n NETWORKS,\n getTxHistory,\n update,\n updateTxHistory,\n} from \"./state.js\";\n\nimport {\n getConfig,\n setConfig,\n resetTxHistory,\n} from \"./state.js\";\n\nimport { sha256 } from \"@noble/hashes/sha2\";\nimport * as reExportAllUtils from \"@fastnear/utils\";\nimport * as stateExports from \"./state.js\";\n\nBig.DP = 27;\nexport const MaxBlockDelayMs = 1000 * 60 * 60 * 6; // 6 hours\n\nexport interface AccessKeyWithError {\n result: {\n nonce: number;\n permission?: any;\n error?: string;\n }\n}\n\nexport interface WalletTxResult {\n url?: string;\n outcomes?: Array<{ transaction: { hash: string } }>;\n rejected?: boolean;\n error?: string;\n}\n\nexport interface BlockView {\n result: {\n header: {\n hash: string;\n timestamp_nanosec: string;\n }\n }\n}\n\n// The structure it's saved to in storage\nexport interface LastKnownBlock {\n header: {\n hash: string;\n timestamp_nanosec: string;\n }\n}\n\nexport function withBlockId(params: Record, blockId?: string) {\n if (blockId === \"final\" || blockId === \"optimistic\") {\n return { ...params, finality: blockId };\n }\n return blockId ? { ...params, block_id: blockId } : { ...params, finality: \"optimistic\" };\n}\n\nexport async function sendRpc(method: string, params: Record | any[]) {\n const config = getConfig();\n if (!config?.nodeUrl) {\n throw new Error(\"fastnear: getConfig() returned invalid config: missing nodeUrl.\");\n }\n const response = await fetch(config.nodeUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: `fastnear-${Date.now()}`,\n method,\n params,\n }),\n });\n const result = await response.json();\n if (result.error) {\n throw new Error(JSON.stringify(result.error));\n }\n return result;\n}\n\nexport function afterTxSent(txId: string) {\n const txHistory = getTxHistory();\n sendRpc(\"tx\", {\n tx_hash: txHistory[txId]?.txHash,\n sender_account_id: txHistory[txId]?.tx?.signerId,\n wait_until: \"EXECUTED_OPTIMISTIC\",\n })\n .then( result => {\n const successValue = result?.result?.status?.SuccessValue;\n updateTxHistory({\n txId,\n status: \"Executed\",\n result,\n successValue: successValue ? tryParseJson(fromBase64(successValue)) : undefined,\n finalState: true,\n });\n })\n .catch((error) => {\n updateTxHistory({\n txId,\n status: \"ErrorAfterIncluded\",\n error: tryParseJson(error.message) ?? error.message,\n finalState: true,\n });\n });\n}\n\nexport async function sendTxToRpc(signedTxBase64: string, waitUntil: string | undefined, txId: string) {\n // default to \"INCLUDED\"\n // see options: https://docs.near.org/api/rpc/transactions#tx-status-result\n waitUntil = waitUntil || \"INCLUDED\";\n\n try {\n const sendTxRes = await sendRpc(\"send_tx\", {\n signed_tx_base64: signedTxBase64,\n wait_until: waitUntil,\n });\n\n updateTxHistory({ txId, status: \"Included\", finalState: false });\n afterTxSent(txId);\n\n return sendTxRes;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n updateTxHistory({\n txId,\n status: \"Error\",\n error: tryParseJson(errorMessage) ?? errorMessage,\n finalState: false,\n });\n throw new Error(errorMessage);\n }\n}\n\nexport interface AccessKeyView {\n nonce: number;\n permission: any;\n}\n\n/**\n * Generates a mock transaction ID.\n *\n * This function creates a pseudo-unique transaction ID for testing or\n * non-production use. It combines the current timestamp with a\n * random component for uniqueness.\n *\n * **Note:** This is not cryptographically secure and should not be used\n * for actual transaction processing.\n *\n * @returns {string} A mock transaction ID in the format `tx-{timestamp}-{random}`\n */\nexport function generateTxId(): string {\n const randomPart = crypto.getRandomValues(new Uint32Array(2)).join(\"\");\n return `tx-${Date.now()}-${parseInt(randomPart, 10).toString(36)}`;\n}\n\nexport const accountId = () => _state.accountId;\nexport const publicKey = () => _state.publicKey;\n\nexport const config = (newConfig?: Record) => {\n const current = getConfig();\n if (newConfig) {\n if (newConfig.networkId && current.networkId !== newConfig.networkId) {\n setConfig(newConfig.networkId);\n update({ accountId: null, privateKey: null, lastWalletId: null });\n lsSet(\"block\", null);\n resetTxHistory();\n }\n setConfig({ ...getConfig(), ...newConfig });\n }\n return getConfig();\n};\n\nexport const authStatus = (): string | Record => {\n if (!_state.accountId) {\n return \"SignedOut\";\n }\n return \"SignedIn\";\n};\n\n// this is an intentional stub\n// and it's probably partially done, to help ease future features\n// for now we'll assume each web end user has one keypair in storage\n// for every contract they wish to interact with\n// later, it may be prudent to hold multiple, but until then this function\n// just returns the access key as if it were among others in the array.\n// we're pretending like we really thought about which access key we're returning\n// based on the opts argument. this allows us to fill this logic in later.\nexport const getPublicKeyForContract = (opts?: any) => {\n return publicKey();\n}\n\n// returns details on the selected:\n// network, wallet, and explorer details as well as\n// sending account, contract, and selected public key\nexport const selected = () => {\n const network = getConfig().networkId;\n const nodeUrl = getConfig().nodeUrl;\n const walletUrl = getConfig().walletUrl;\n const helperUrl = getConfig().helperUrl;\n const explorerUrl = getConfig().explorerUrl;\n\n const account = accountId();\n const contract = _state.accessKeyContractId;\n const publicKey = getPublicKeyForContract();\n\n return {\n network,\n nodeUrl,\n walletUrl,\n helperUrl,\n explorerUrl,\n account,\n contract,\n publicKey\n }\n}\n\nexport const requestSignIn = async ({ contractId }: { contractId: string }) => {\n const privateKey = privateKeyFromRandom();\n update({ accessKeyContractId: contractId, accountId: null, privateKey });\n const pubKey = publicKeyFromPrivate(privateKey);\n\n const result = await _adapter.signIn({\n networkId: getConfig().networkId,\n contractId,\n publicKey: pubKey,\n });\n\n if (result.error) {\n throw new Error(`Wallet error: ${result.error}`);\n }\n if (result.url) {\n if (typeof window !== \"undefined\") {\n setTimeout(() => {\n window.location.href = result.url;\n }, 100);\n }\n } else if (result.accountId) {\n update({ accountId: result.accountId });\n }\n};\n\nexport const view = async ({\n contractId,\n methodName,\n args,\n argsBase64,\n blockId,\n }: {\n contractId: string;\n methodName: string;\n args?: any;\n argsBase64?: string;\n blockId?: string;\n}) => {\n const encodedArgs = argsBase64 || (args ? toBase64(JSON.stringify(args)) : \"\");\n const queryResult = await sendRpc(\n \"query\",\n withBlockId(\n {\n request_type: \"call_function\",\n account_id: contractId,\n method_name: methodName,\n args_base64: encodedArgs,\n },\n blockId\n )\n );\n\n return parseJsonFromBytes(queryResult.result.result);\n};\n\nexport const queryAccount = async ({\n accountId,\n blockId,\n }: {\n accountId: string;\n blockId?: string;\n}) => {\n return sendRpc(\n \"query\",\n withBlockId({ request_type: \"view_account\", account_id: accountId }, blockId)\n );\n};\n\nexport const queryBlock = async ({ blockId }: { blockId?: string }): Promise => {\n return sendRpc(\"block\", withBlockId({}, blockId));\n};\n\nexport const queryAccessKey = async ({\n accountId,\n publicKey,\n blockId,\n }: {\n accountId: string;\n publicKey: string;\n blockId?: string;\n}): Promise => {\n return sendRpc(\n \"query\",\n withBlockId(\n { request_type: \"view_access_key\", account_id: accountId, public_key: publicKey },\n blockId\n )\n );\n};\n\nexport const queryTx = async ({ txHash, accountId }: { txHash: string; accountId: string }) => {\n return sendRpc(\"tx\", [txHash, accountId]);\n};\n\nexport const localTxHistory = () => {\n return getTxHistory();\n};\n\nexport const signOut = () => {\n update({ accountId: null, privateKey: null, contractId: null });\n setConfig(NETWORKS[DEFAULT_NETWORK_ID]);\n};\n\nexport const sendTx = async ({\n receiverId,\n actions,\n waitUntil,\n }: {\n receiverId: string;\n actions: any[];\n waitUntil?: string;\n}) => {\n const signerId = _state.accountId;\n if (!signerId) throw new Error(\"Must sign in\");\n\n const publicKey = _state.publicKey ?? \"\";\n const privKey = _state.privateKey;\n // this generates a mock transaction ID so we can keep track of each tx\n const txId = generateTxId();\n\n if (!privKey || receiverId !== _state.accessKeyContractId || !canSignWithLAK(actions)) {\n const jsonTx = { signerId, receiverId, actions };\n updateTxHistory({ status: \"Pending\", txId, tx: jsonTx, finalState: false });\n\n const url = new URL(typeof window !== \"undefined\" ? window.location.href : \"\");\n url.searchParams.set(\"txIds\", txId);\n\n // preserve existing url params\n const existingParams = new URLSearchParams(window.location.search);\n existingParams.forEach((value, key) => {\n if (!url.searchParams.has(key)) {\n url.searchParams.set(key, value);\n }\n });\n\n // we're wanting to preserve URL params that we send in\n // but make sure we're not feeding back error params\n // from a previous failure\n\n url.searchParams.delete(\"errorCode\");\n url.searchParams.delete(\"errorMessage\");\n\n try {\n const result: WalletTxResult = await _adapter.sendTransactions({\n transactions: [jsonTx],\n callbackUrl: url.toString(),\n });\n\n if (result.url) {\n if (typeof window !== \"undefined\") {\n setTimeout(() => {\n window.location.href = result.url!;\n }, 100);\n }\n } else if (result.outcomes?.length) {\n result.outcomes.forEach((r) =>\n updateTxHistory({\n txId,\n status: \"Executed\",\n result: r,\n txHash: r.transaction.hash,\n finalState: true,\n })\n );\n } else if (result.rejected) {\n updateTxHistory({ txId, status: \"RejectedByUser\", finalState: true });\n } else if (result.error) {\n updateTxHistory({\n txId,\n status: \"Error\",\n error: tryParseJson(result.error),\n finalState: true,\n });\n }\n\n return result;\n } catch (err) {\n console.error('fastnear: error sending tx using adapter:', err)\n updateTxHistory({\n txId,\n status: \"Error\",\n error: tryParseJson((err as Error).message),\n finalState: true,\n });\n\n return Promise.reject(err);\n }\n }\n\n let nonce = lsGet(\"nonce\") as number | null;\n if (nonce == null) {\n const accessKey = await queryAccessKey({ accountId: signerId, publicKey: publicKey });\n if (accessKey.result.error) {\n throw new Error(`Access key error: ${accessKey.result.error} when attempting to get nonce for ${signerId} for public key ${publicKey}`);\n }\n nonce = accessKey.result.nonce;\n lsSet(\"nonce\", nonce);\n }\n\n let lastKnownBlock = lsGet(\"block\") as LastKnownBlock | null;\n if (\n !lastKnownBlock ||\n parseFloat(lastKnownBlock.header.timestamp_nanosec) / 1e6 + MaxBlockDelayMs < Date.now()\n ) {\n const latestBlock = await queryBlock({ blockId: \"final\" });\n lastKnownBlock = {\n header: {\n hash: latestBlock.result.header.hash,\n timestamp_nanosec: latestBlock.result.header.timestamp_nanosec,\n },\n };\n lsSet(\"block\", lastKnownBlock);\n }\n\n nonce += 1;\n lsSet(\"nonce\", nonce);\n\n const blockHash = lastKnownBlock.header.hash;\n\n const plainTransactionObj: PlainTransaction = {\n signerId,\n publicKey,\n nonce,\n receiverId,\n blockHash,\n actions,\n };\n\n const txBytes = serializeTransaction(plainTransactionObj);\n const txHashBytes = sha256(txBytes);\n const txHash58 = toBase58(txHashBytes);\n\n const signatureBase58 = signHash(txHashBytes, privKey, { returnBase58: true });\n const signedTransactionBytes = serializeSignedTransaction(plainTransactionObj, signatureBase58);\n const signedTxBase64 = bytesToBase64(signedTransactionBytes);\n\n updateTxHistory({\n status: \"Pending\",\n txId,\n tx: plainTransactionObj,\n signature: signatureBase58,\n signedTxBase64,\n txHash: txHash58,\n finalState: false,\n });\n\n try {\n return await sendTxToRpc(signedTxBase64, waitUntil, txId);\n } catch (error) {\n console.error(\"Error Sending Transaction:\", error, plainTransactionObj, signedTxBase64);\n }\n};\n\n// exports\nexport const exp = {\n utils: {}, // we will map this in a moment, giving keys, for IDE hints\n borsh: reExportAllUtils.exp.borsh,\n borshSchema: reExportAllUtils.exp.borshSchema.getBorshSchema(),\n};\n\nfor (const key in reExportAllUtils) {\n exp.utils[key] = reExportAllUtils[key];\n}\n\n// devx\nexport const utils = exp.utils;\n\nexport const state = {}\n\nfor (const key in stateExports) {\n state[key] = stateExports[key];\n}\n\n// devx\n\nexport const event = state['events'];\ndelete state['events'];\n\n// Wallet redirect handling\ntry {\n if (typeof window !== \"undefined\") {\n const url = new URL(window.location.href);\n const accId = url.searchParams.get(\"account_id\");\n const pubKey = url.searchParams.get(\"public_key\");\n const errCode = url.searchParams.get(\"errorCode\");\n const errMsg = url.searchParams.get(\"errorMessage\");\n const decodedErrMsg = errMsg ? decodeURIComponent(errMsg) : null;\n\n const txHashes = url.searchParams.get(\"transactionHashes\");\n const txIds = url.searchParams.get(\"txIds\");\n\n if (errCode || errMsg) {\n console.warn(new Error(`Wallet raises:\\ncode: ${errCode}\\nmessage: ${decodedErrMsg}`));\n }\n\n if (accId && pubKey) {\n if (pubKey === _state.publicKey) {\n update({ accountId: accId });\n } else {\n // it's possible the end user has a URL param that's old. we'll remove the public_key param\n // if logged out, no need to throw warning\n if (authStatus() === \"SignedIn\") {\n console.warn(\"Public key mismatch from wallet redirect\", pubKey, _state.publicKey);\n }\n url.searchParams.delete(\"public_key\");\n }\n }\n\n if (txHashes || txIds) {\n const hashArr = txHashes ? txHashes.split(\",\") : [];\n const idArr = txIds ? txIds.split(\",\") : [];\n if (idArr.length > hashArr.length) {\n idArr.forEach((id) => {\n updateTxHistory({ txId: id, status: \"RejectedByUser\", finalState: true });\n });\n } else if (idArr.length === hashArr.length) {\n idArr.forEach((id, i) => {\n updateTxHistory({\n txId: id,\n status: \"PendingGotTxHash\",\n txHash: hashArr[i],\n finalState: false,\n });\n afterTxSent(id);\n });\n } else {\n console.error(new Error(\"Transaction hash mismatch from wallet redirect\"), idArr, hashArr);\n }\n }\n\n // we can consider removing these, but want to be careful because\n // it can be helpful for a dev to have a URL they can debug with\n // we won't want to remove information\n\n // pretty sure txIds can go, especially if you can tell it's been more than 5 minutes or something\n // public_key sometimes confuses it, so this might only be needed when adding a new access key\n // and perhaps once we've confirmed that the transaction hashes are getting saved to storage\n // (not sure about that section of code) then we can get rid of the transactionHashes, too\n\n url.searchParams.delete(\"txIds\");\n if (authStatus() === \"SignedOut\") {\n url.searchParams.delete(\"errorCode\");\n url.searchParams.delete(\"errorMessage\");\n }\n // ^ we've decided these ones make sense to keep\n\n // I'd like to keep this for posterity. for a bit.\n // url.searchParams.delete(\"account_id\");\n // url.searchParams.delete(\"public_key\");\n\n // url.searchParams.delete(\"all_keys\");\n // url.searchParams.delete(\"transactionHashes\");\n // window.history.replaceState({}, \"\", url.toString());\n }\n} catch (e) {\n console.error(\"Error handling wallet redirect:\", e);\n}\n\n// action helpers\nexport const actions = {\n functionCall: ({\n methodName,\n gas,\n deposit,\n args,\n argsBase64,\n }: {\n methodName: string;\n gas?: string;\n deposit?: string;\n args?: Record;\n argsBase64?: string;\n }) => ({\n type: \"FunctionCall\",\n methodName,\n args,\n argsBase64,\n gas,\n deposit,\n }),\n\n transfer: (yoctoAmount: string) => ({\n type: \"Transfer\",\n deposit: yoctoAmount,\n }),\n\n stakeNEAR: ({amount, publicKey}: { amount: string; publicKey: string }) => ({\n type: \"Stake\",\n stake: amount,\n publicKey,\n }),\n\n addFullAccessKey: ({publicKey}: { publicKey: string }) => ({\n type: \"AddKey\",\n publicKey: publicKey,\n accessKey: {permission: \"FullAccess\"},\n }),\n\n addLimitedAccessKey: ({\n publicKey,\n allowance,\n accountId,\n methodNames,\n }: {\n publicKey: string;\n allowance: string;\n accountId: string;\n methodNames: string[];\n }) => ({\n type: \"AddKey\",\n publicKey: publicKey,\n accessKey: {\n permission: \"FunctionCall\",\n allowance,\n receiverId: accountId,\n methodNames,\n },\n }),\n\n deleteKey: ({publicKey}: { publicKey: string }) => ({\n type: \"DeleteKey\",\n publicKey,\n }),\n\n deleteAccount: ({beneficiaryId}: { beneficiaryId: string }) => ({\n type: \"DeleteAccount\",\n beneficiaryId,\n }),\n\n createAccount: () => ({\n type: \"CreateAccount\",\n }),\n\n deployContract: ({codeBase64}: { codeBase64: string }) => ({\n type: \"DeployContract\",\n codeBase64,\n }),\n};\n"],"mappings":"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","names":["config","publicKey","accountId","actions"]} \ No newline at end of file diff --git a/static/js-loaded-globally/nearjs/0.9.7/esm/state.js b/static/js-loaded-globally/nearjs/0.9.7/esm/state.js deleted file mode 100644 index 634b993..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/esm/state.js +++ /dev/null @@ -1,172 +0,0 @@ -/* ⋈ 🏃🏻💨 FastNear API - ESM (@fastnear/api version 0.9.7) */ -/* https://www.npmjs.com/package/@fastnear/api/v/0.9.7 */ -var __defProp = Object.defineProperty; -var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); -import { - lsSet, - lsGet, - publicKeyFromPrivate -} from "@fastnear/utils"; -import { WalletAdapter } from "@fastnear/wallet-adapter"; -const WIDGET_URL = "https://js.cdn.fastnear.com"; -const DEFAULT_NETWORK_ID = "mainnet"; -const NETWORKS = { - testnet: { - networkId: "testnet", - nodeUrl: "https://rpc.testnet.fastnear.com/" - }, - mainnet: { - networkId: "mainnet", - nodeUrl: "https://rpc.mainnet.fastnear.com/" - } -}; -let _config = lsGet("config") || { - ...NETWORKS[DEFAULT_NETWORK_ID] -}; -let _state = lsGet("state") || {}; -const onAdapterStateUpdate = /* @__PURE__ */ __name((state) => { - console.log("Adapter state update:", state); - const { accountId, lastWalletId, privateKey } = state; - update({ - accountId: accountId || void 0, - lastWalletId: lastWalletId || void 0, - ...privateKey ? { privateKey } : {} - }); -}, "onAdapterStateUpdate"); -const getWalletAdapterState = /* @__PURE__ */ __name(() => { - return { - publicKey: _state.publicKey, - accountId: _state.accountId, - lastWalletId: _state.lastWalletId, - networkId: _config.networkId - }; -}, "getWalletAdapterState"); -let _adapter = new WalletAdapter({ - onStateUpdate: onAdapterStateUpdate, - lastState: getWalletAdapterState(), - widgetUrl: WIDGET_URL -}); -try { - _state.publicKey = _state.privateKey ? publicKeyFromPrivate(_state.privateKey) : null; -} catch (e) { - console.error("Error parsing private key:", e); - _state.privateKey = null; - lsSet("nonce", null); -} -let _txHistory = lsGet("txHistory") || {}; -const _unbroadcastedEvents = { - account: [], - tx: [] -}; -const events = { - _eventListeners: { - account: /* @__PURE__ */ new Set(), - tx: /* @__PURE__ */ new Set() - }, - notifyAccountListeners: /* @__PURE__ */ __name((accountId) => { - if (events._eventListeners.account.size === 0) { - _unbroadcastedEvents.account.push(accountId); - return; - } - events._eventListeners.account.forEach((callback) => { - try { - callback(accountId); - } catch (e) { - console.error(e); - } - }); - }, "notifyAccountListeners"), - notifyTxListeners: /* @__PURE__ */ __name((tx) => { - if (events._eventListeners.tx.size === 0) { - _unbroadcastedEvents.tx.push(tx); - return; - } - events._eventListeners.tx.forEach((callback) => { - try { - callback(tx); - } catch (e) { - console.error(e); - } - }); - }, "notifyTxListeners"), - onAccount: /* @__PURE__ */ __name((callback) => { - events._eventListeners.account.add(callback); - if (_unbroadcastedEvents.account.length > 0) { - const accountEvent = _unbroadcastedEvents.account; - _unbroadcastedEvents.account = []; - accountEvent.forEach(events.notifyAccountListeners); - } - }, "onAccount"), - onTx: /* @__PURE__ */ __name((callback) => { - events._eventListeners.tx.add(callback); - if (_unbroadcastedEvents.tx.length > 0) { - const txEvent = _unbroadcastedEvents.tx; - _unbroadcastedEvents.tx = []; - txEvent.forEach(events.notifyTxListeners); - } - }, "onTx") -}; -const update = /* @__PURE__ */ __name((newState) => { - const oldState = _state; - _state = { ..._state, ...newState }; - lsSet("state", { - accountId: _state.accountId, - privateKey: _state.privateKey, - lastWalletId: _state.lastWalletId, - accessKeyContractId: _state.accessKeyContractId - }); - if (newState.hasOwnProperty("privateKey") && newState.privateKey !== oldState.privateKey) { - _state.publicKey = newState.privateKey ? publicKeyFromPrivate(newState.privateKey) : null; - lsSet("nonce", null); - } - if (newState.accountId !== oldState.accountId) { - events.notifyAccountListeners(newState.accountId); - } - if (newState.hasOwnProperty("lastWalletId") && newState.lastWalletId !== oldState.lastWalletId || newState.hasOwnProperty("accountId") && newState.accountId !== oldState.accountId || newState.hasOwnProperty("privateKey") && newState.privateKey !== oldState.privateKey) { - _adapter.setState(getWalletAdapterState()); - } -}, "update"); -const updateTxHistory = /* @__PURE__ */ __name((txStatus) => { - const txId = txStatus.txId; - _txHistory[txId] = { - ..._txHistory[txId] || {}, - ...txStatus, - updateTimestamp: Date.now() - }; - lsSet("txHistory", _txHistory); - events.notifyTxListeners(_txHistory[txId]); -}, "updateTxHistory"); -const getConfig = /* @__PURE__ */ __name(() => { - return _config; -}, "getConfig"); -const getTxHistory = /* @__PURE__ */ __name(() => { - return _txHistory; -}, "getTxHistory"); -const setConfig = /* @__PURE__ */ __name((newConf) => { - _config = { ...NETWORKS[newConf.networkId], ...newConf }; - lsSet("config", _config); -}, "setConfig"); -const resetTxHistory = /* @__PURE__ */ __name(() => { - _txHistory = {}; - lsSet("txHistory", _txHistory); -}, "resetTxHistory"); -export { - DEFAULT_NETWORK_ID, - NETWORKS, - WIDGET_URL, - _adapter, - _config, - _state, - _txHistory, - _unbroadcastedEvents, - events, - getConfig, - getTxHistory, - getWalletAdapterState, - onAdapterStateUpdate, - resetTxHistory, - setConfig, - update, - updateTxHistory -}; -//# sourceMappingURL=state.js.map diff --git a/static/js-loaded-globally/nearjs/0.9.7/esm/state.js.map b/static/js-loaded-globally/nearjs/0.9.7/esm/state.js.map deleted file mode 100644 index c970fe7..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/esm/state.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["../../src/state.ts"],"sourcesContent":["import {\n lsSet,\n lsGet,\n publicKeyFromPrivate,\n} from \"@fastnear/utils\";\nimport {WalletAdapter} from \"@fastnear/wallet-adapter\";\n\nexport const WIDGET_URL = \"https://js.cdn.fastnear.com\";\n\nexport const DEFAULT_NETWORK_ID = \"mainnet\";\nexport const NETWORKS = {\n testnet: {\n networkId: \"testnet\",\n nodeUrl: \"https://rpc.testnet.fastnear.com/\",\n },\n mainnet: {\n networkId: \"mainnet\",\n nodeUrl: \"https://rpc.mainnet.fastnear.com/\",\n },\n};\n\nexport interface NetworkConfig {\n networkId: string;\n nodeUrl?: string;\n walletUrl?: string;\n helperUrl?: string;\n explorerUrl?: string;\n\n [key: string]: any;\n}\n\nexport interface AppState {\n accountId?: string | null;\n privateKey?: string | null;\n lastWalletId?: string | null;\n publicKey?: string | null;\n accessKeyContractId?: string | null;\n\n [key: string]: any;\n}\n\nexport interface TxStatus {\n txId: string;\n updateTimestamp?: number;\n\n [key: string]: any;\n}\n\nexport type TxHistory = Record;\n\nexport interface EventListeners {\n account: Set<(accountId: string) => void>;\n tx: Set<(tx: TxStatus) => void>;\n}\n\nexport interface UnbroadcastedEvents {\n account: string[];\n tx: TxStatus[];\n}\n\nexport interface WalletAdapterState {\n publicKey?: string | null;\n privateKey?: string | null;\n accountId?: string | null;\n lastWalletId?: string | null;\n networkId: string;\n}\n\n\n// Load config from localStorage or default to the network's config\nexport let _config: NetworkConfig = lsGet(\"config\") || {\n ...NETWORKS[DEFAULT_NETWORK_ID]\n};\n\n// Load application state from localStorage\nexport let _state: AppState = lsGet(\"state\") || {};\n\n// Triggered by the wallet adapter\nexport const onAdapterStateUpdate = (state: WalletAdapterState) => {\n console.log(\"Adapter state update:\", state);\n const { accountId, lastWalletId, privateKey } = state;\n update({\n accountId: accountId || undefined,\n lastWalletId: lastWalletId || undefined,\n ...(privateKey ? { privateKey } : {}),\n });\n}\n\nexport const getWalletAdapterState = (): WalletAdapterState => {\n return {\n publicKey: _state.publicKey,\n accountId: _state.accountId,\n lastWalletId: _state.lastWalletId,\n networkId: _config.networkId,\n };\n}\n\n// We can create an adapter instance here\nexport let _adapter = new WalletAdapter({\n onStateUpdate: onAdapterStateUpdate,\n lastState: getWalletAdapterState(),\n widgetUrl: WIDGET_URL,\n});\n\n// Attempt to set publicKey if we have a privateKey\ntry {\n _state.publicKey = _state.privateKey\n ? publicKeyFromPrivate(_state.privateKey)\n : null;\n} catch (e) {\n console.error(\"Error parsing private key:\", e);\n _state.privateKey = null;\n lsSet(\"nonce\", null);\n}\n\n// Transaction history\nexport let _txHistory: TxHistory = lsGet(\"txHistory\") || {};\n\n\nexport const _unbroadcastedEvents: UnbroadcastedEvents = {\n account: [],\n tx: [],\n};\n\n// events / listeners\nexport const events = {\n _eventListeners: {\n account: new Set(),\n tx: new Set(),\n },\n\n notifyAccountListeners: (accountId: string) => {\n if (events._eventListeners.account.size === 0) {\n _unbroadcastedEvents.account.push(accountId);\n return;\n }\n events._eventListeners.account.forEach((callback: any) => {\n try {\n callback(accountId);\n } catch (e) {\n console.error(e);\n }\n });\n },\n\n notifyTxListeners: (tx: TxStatus) => {\n if (events._eventListeners.tx.size === 0) {\n _unbroadcastedEvents.tx.push(tx);\n return;\n }\n events._eventListeners.tx.forEach((callback: any) => {\n try {\n callback(tx);\n } catch (e) {\n console.error(e);\n }\n });\n },\n\n onAccount: (callback: (accountId: string) => void) => {\n events._eventListeners.account.add(callback);\n if (_unbroadcastedEvents.account.length > 0) {\n const accountEvent = _unbroadcastedEvents.account;\n _unbroadcastedEvents.account = [];\n accountEvent.forEach(events.notifyAccountListeners);\n }\n },\n\n onTx: (callback: (tx: TxStatus) => void): void => {\n events._eventListeners.tx.add(callback);\n if (_unbroadcastedEvents.tx.length > 0) {\n const txEvent = _unbroadcastedEvents.tx;\n _unbroadcastedEvents.tx = [];\n txEvent.forEach(events.notifyTxListeners);\n }\n }\n}\n\n// Mutators\n// @todo: in favor of limiting when out of alpha\n// but haven't given it enough thought ~ mike\nexport const update = (newState: Partial) => {\n const oldState = _state;\n _state = {..._state, ...newState};\n\n lsSet(\"state\", {\n accountId: _state.accountId,\n privateKey: _state.privateKey,\n lastWalletId: _state.lastWalletId,\n accessKeyContractId: _state.accessKeyContractId,\n });\n\n if (\n newState.hasOwnProperty(\"privateKey\") &&\n newState.privateKey !== oldState.privateKey\n ) {\n _state.publicKey = newState.privateKey\n ? publicKeyFromPrivate(newState.privateKey as string)\n : null;\n lsSet(\"nonce\", null);\n }\n\n if (newState.accountId !== oldState.accountId) {\n events.notifyAccountListeners(newState.accountId as string);\n }\n\n if (\n (newState.hasOwnProperty(\"lastWalletId\") &&\n newState.lastWalletId !== oldState.lastWalletId) ||\n (newState.hasOwnProperty(\"accountId\") &&\n newState.accountId !== oldState.accountId) ||\n (newState.hasOwnProperty(\"privateKey\") &&\n newState.privateKey !== oldState.privateKey)\n ) {\n _adapter.setState(getWalletAdapterState());\n }\n}\n\nexport const updateTxHistory = (txStatus: TxStatus) => {\n const txId = txStatus.txId;\n _txHistory[txId] = {\n ...(_txHistory[txId] || {}),\n ...txStatus,\n updateTimestamp: Date.now(),\n };\n lsSet(\"txHistory\", _txHistory);\n events.notifyTxListeners(_txHistory[txId]);\n}\n\nexport const getConfig = (): NetworkConfig => {\n return _config;\n}\n\nexport const getTxHistory = (): TxHistory => {\n return _txHistory;\n}\n\n// Exposed \"write\" functions\nexport const setConfig = (newConf: NetworkConfig): void => {\n _config = { ...NETWORKS[newConf.networkId], ...newConf };\n lsSet(\"config\", _config);\n}\n\nexport const resetTxHistory = (): void => {\n _txHistory = {};\n lsSet(\"txHistory\", _txHistory);\n}\n"],"mappings":"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","names":[]} \ No newline at end of file diff --git a/static/js-loaded-globally/nearjs/0.9.7/umd/browser.global.js b/static/js-loaded-globally/nearjs/0.9.7/umd/browser.global.js deleted file mode 100644 index f4d0f26..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/umd/browser.global.js +++ /dev/null @@ -1,4379 +0,0 @@ -/* ⋈ 🏃🏻💨 FastNear API - IIFE/UMD (@fastnear/api version 0.9.7) */ -/* https://www.npmjs.com/package/@fastnear/api/v/0.9.7 */ -"use strict"; -var near = (() => { - var __defProp = Object.defineProperty; - var __getOwnPropDesc = Object.getOwnPropertyDescriptor; - var __getOwnPropNames = Object.getOwnPropertyNames; - var __hasOwnProp = Object.prototype.hasOwnProperty; - var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); - var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); - }; - var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; - }; - var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2); - - // src/index.ts - var src_exports3 = {}; - __export(src_exports3, { - MaxBlockDelayMs: () => MaxBlockDelayMs, - accountId: () => accountId, - actions: () => actions, - afterTxSent: () => afterTxSent, - authStatus: () => authStatus, - config: () => config, - event: () => event, - exp: () => exp2, - generateTxId: () => generateTxId, - getPublicKeyForContract: () => getPublicKeyForContract, - localTxHistory: () => localTxHistory, - publicKey: () => publicKey, - queryAccessKey: () => queryAccessKey, - queryAccount: () => queryAccount, - queryBlock: () => queryBlock, - queryTx: () => queryTx, - requestSignIn: () => requestSignIn, - selected: () => selected, - sendRpc: () => sendRpc, - sendTx: () => sendTx, - sendTxToRpc: () => sendTxToRpc, - signOut: () => signOut, - state: () => state, - utils: () => utils, - view: () => view, - withBlockId: () => withBlockId - }); - - // ../../node_modules/big.js/big.mjs - var DP = 20; - var RM = 1; - var MAX_DP = 1e6; - var MAX_POWER = 1e6; - var NE = -7; - var PE = 21; - var STRICT = false; - var NAME = "[big.js] "; - var INVALID = NAME + "Invalid "; - var INVALID_DP = INVALID + "decimal places"; - var INVALID_RM = INVALID + "rounding mode"; - var DIV_BY_ZERO = NAME + "Division by zero"; - var P = {}; - var UNDEFINED = void 0; - var NUMERIC = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i; - function _Big_() { - function Big2(n) { - var x = this; - if (!(x instanceof Big2)) return n === UNDEFINED ? _Big_() : new Big2(n); - if (n instanceof Big2) { - x.s = n.s; - x.e = n.e; - x.c = n.c.slice(); - } else { - if (typeof n !== "string") { - if (Big2.strict === true && typeof n !== "bigint") { - throw TypeError(INVALID + "value"); - } - n = n === 0 && 1 / n < 0 ? "-0" : String(n); - } - parse(x, n); - } - x.constructor = Big2; - } - __name(Big2, "Big"); - Big2.prototype = P; - Big2.DP = DP; - Big2.RM = RM; - Big2.NE = NE; - Big2.PE = PE; - Big2.strict = STRICT; - Big2.roundDown = 0; - Big2.roundHalfUp = 1; - Big2.roundHalfEven = 2; - Big2.roundUp = 3; - return Big2; - } - __name(_Big_, "_Big_"); - function parse(x, n) { - var e, i, nl; - if (!NUMERIC.test(n)) { - throw Error(INVALID + "number"); - } - x.s = n.charAt(0) == "-" ? (n = n.slice(1), -1) : 1; - if ((e = n.indexOf(".")) > -1) n = n.replace(".", ""); - if ((i = n.search(/e/i)) > 0) { - if (e < 0) e = i; - e += +n.slice(i + 1); - n = n.substring(0, i); - } else if (e < 0) { - e = n.length; - } - nl = n.length; - for (i = 0; i < nl && n.charAt(i) == "0"; ) ++i; - if (i == nl) { - x.c = [x.e = 0]; - } else { - for (; nl > 0 && n.charAt(--nl) == "0"; ) ; - x.e = e - i - 1; - x.c = []; - for (e = 0; i <= nl; ) x.c[e++] = +n.charAt(i++); - } - return x; - } - __name(parse, "parse"); - function round(x, sd, rm, more) { - var xc = x.c; - if (rm === UNDEFINED) rm = x.constructor.RM; - if (rm !== 0 && rm !== 1 && rm !== 2 && rm !== 3) { - throw Error(INVALID_RM); - } - if (sd < 1) { - more = rm === 3 && (more || !!xc[0]) || sd === 0 && (rm === 1 && xc[0] >= 5 || rm === 2 && (xc[0] > 5 || xc[0] === 5 && (more || xc[1] !== UNDEFINED))); - xc.length = 1; - if (more) { - x.e = x.e - sd + 1; - xc[0] = 1; - } else { - xc[0] = x.e = 0; - } - } else if (sd < xc.length) { - more = rm === 1 && xc[sd] >= 5 || rm === 2 && (xc[sd] > 5 || xc[sd] === 5 && (more || xc[sd + 1] !== UNDEFINED || xc[sd - 1] & 1)) || rm === 3 && (more || !!xc[0]); - xc.length = sd; - if (more) { - for (; ++xc[--sd] > 9; ) { - xc[sd] = 0; - if (sd === 0) { - ++x.e; - xc.unshift(1); - break; - } - } - } - for (sd = xc.length; !xc[--sd]; ) xc.pop(); - } - return x; - } - __name(round, "round"); - function stringify(x, doExponential, isNonzero) { - var e = x.e, s = x.c.join(""), n = s.length; - if (doExponential) { - s = s.charAt(0) + (n > 1 ? "." + s.slice(1) : "") + (e < 0 ? "e" : "e+") + e; - } else if (e < 0) { - for (; ++e; ) s = "0" + s; - s = "0." + s; - } else if (e > 0) { - if (++e > n) { - for (e -= n; e--; ) s += "0"; - } else if (e < n) { - s = s.slice(0, e) + "." + s.slice(e); - } - } else if (n > 1) { - s = s.charAt(0) + "." + s.slice(1); - } - return x.s < 0 && isNonzero ? "-" + s : s; - } - __name(stringify, "stringify"); - P.abs = function() { - var x = new this.constructor(this); - x.s = 1; - return x; - }; - P.cmp = function(y) { - var isneg, x = this, xc = x.c, yc = (y = new x.constructor(y)).c, i = x.s, j = y.s, k = x.e, l = y.e; - if (!xc[0] || !yc[0]) return !xc[0] ? !yc[0] ? 0 : -j : i; - if (i != j) return i; - isneg = i < 0; - if (k != l) return k > l ^ isneg ? 1 : -1; - j = (k = xc.length) < (l = yc.length) ? k : l; - for (i = -1; ++i < j; ) { - if (xc[i] != yc[i]) return xc[i] > yc[i] ^ isneg ? 1 : -1; - } - return k == l ? 0 : k > l ^ isneg ? 1 : -1; - }; - P.div = function(y) { - var x = this, Big2 = x.constructor, a = x.c, b = (y = new Big2(y)).c, k = x.s == y.s ? 1 : -1, dp = Big2.DP; - if (dp !== ~~dp || dp < 0 || dp > MAX_DP) { - throw Error(INVALID_DP); - } - if (!b[0]) { - throw Error(DIV_BY_ZERO); - } - if (!a[0]) { - y.s = k; - y.c = [y.e = 0]; - return y; - } - var bl, bt, n, cmp, ri, bz = b.slice(), ai = bl = b.length, al = a.length, r = a.slice(0, bl), rl = r.length, q = y, qc = q.c = [], qi = 0, p = dp + (q.e = x.e - y.e) + 1; - q.s = k; - k = p < 0 ? 0 : p; - bz.unshift(0); - for (; rl++ < bl; ) r.push(0); - do { - for (n = 0; n < 10; n++) { - if (bl != (rl = r.length)) { - cmp = bl > rl ? 1 : -1; - } else { - for (ri = -1, cmp = 0; ++ri < bl; ) { - if (b[ri] != r[ri]) { - cmp = b[ri] > r[ri] ? 1 : -1; - break; - } - } - } - if (cmp < 0) { - for (bt = rl == bl ? b : bz; rl; ) { - if (r[--rl] < bt[rl]) { - ri = rl; - for (; ri && !r[--ri]; ) r[ri] = 9; - --r[ri]; - r[rl] += 10; - } - r[rl] -= bt[rl]; - } - for (; !r[0]; ) r.shift(); - } else { - break; - } - } - qc[qi++] = cmp ? n : ++n; - if (r[0] && cmp) r[rl] = a[ai] || 0; - else r = [a[ai]]; - } while ((ai++ < al || r[0] !== UNDEFINED) && k--); - if (!qc[0] && qi != 1) { - qc.shift(); - q.e--; - p--; - } - if (qi > p) round(q, p, Big2.RM, r[0] !== UNDEFINED); - return q; - }; - P.eq = function(y) { - return this.cmp(y) === 0; - }; - P.gt = function(y) { - return this.cmp(y) > 0; - }; - P.gte = function(y) { - return this.cmp(y) > -1; - }; - P.lt = function(y) { - return this.cmp(y) < 0; - }; - P.lte = function(y) { - return this.cmp(y) < 1; - }; - P.minus = P.sub = function(y) { - var i, j, t, xlty, x = this, Big2 = x.constructor, a = x.s, b = (y = new Big2(y)).s; - if (a != b) { - y.s = -b; - return x.plus(y); - } - var xc = x.c.slice(), xe = x.e, yc = y.c, ye = y.e; - if (!xc[0] || !yc[0]) { - if (yc[0]) { - y.s = -b; - } else if (xc[0]) { - y = new Big2(x); - } else { - y.s = 1; - } - return y; - } - if (a = xe - ye) { - if (xlty = a < 0) { - a = -a; - t = xc; - } else { - ye = xe; - t = yc; - } - t.reverse(); - for (b = a; b--; ) t.push(0); - t.reverse(); - } else { - j = ((xlty = xc.length < yc.length) ? xc : yc).length; - for (a = b = 0; b < j; b++) { - if (xc[b] != yc[b]) { - xlty = xc[b] < yc[b]; - break; - } - } - } - if (xlty) { - t = xc; - xc = yc; - yc = t; - y.s = -y.s; - } - if ((b = (j = yc.length) - (i = xc.length)) > 0) for (; b--; ) xc[i++] = 0; - for (b = i; j > a; ) { - if (xc[--j] < yc[j]) { - for (i = j; i && !xc[--i]; ) xc[i] = 9; - --xc[i]; - xc[j] += 10; - } - xc[j] -= yc[j]; - } - for (; xc[--b] === 0; ) xc.pop(); - for (; xc[0] === 0; ) { - xc.shift(); - --ye; - } - if (!xc[0]) { - y.s = 1; - xc = [ye = 0]; - } - y.c = xc; - y.e = ye; - return y; - }; - P.mod = function(y) { - var ygtx, x = this, Big2 = x.constructor, a = x.s, b = (y = new Big2(y)).s; - if (!y.c[0]) { - throw Error(DIV_BY_ZERO); - } - x.s = y.s = 1; - ygtx = y.cmp(x) == 1; - x.s = a; - y.s = b; - if (ygtx) return new Big2(x); - a = Big2.DP; - b = Big2.RM; - Big2.DP = Big2.RM = 0; - x = x.div(y); - Big2.DP = a; - Big2.RM = b; - return this.minus(x.times(y)); - }; - P.neg = function() { - var x = new this.constructor(this); - x.s = -x.s; - return x; - }; - P.plus = P.add = function(y) { - var e, k, t, x = this, Big2 = x.constructor; - y = new Big2(y); - if (x.s != y.s) { - y.s = -y.s; - return x.minus(y); - } - var xe = x.e, xc = x.c, ye = y.e, yc = y.c; - if (!xc[0] || !yc[0]) { - if (!yc[0]) { - if (xc[0]) { - y = new Big2(x); - } else { - y.s = x.s; - } - } - return y; - } - xc = xc.slice(); - if (e = xe - ye) { - if (e > 0) { - ye = xe; - t = yc; - } else { - e = -e; - t = xc; - } - t.reverse(); - for (; e--; ) t.push(0); - t.reverse(); - } - if (xc.length - yc.length < 0) { - t = yc; - yc = xc; - xc = t; - } - e = yc.length; - for (k = 0; e; xc[e] %= 10) k = (xc[--e] = xc[e] + yc[e] + k) / 10 | 0; - if (k) { - xc.unshift(k); - ++ye; - } - for (e = xc.length; xc[--e] === 0; ) xc.pop(); - y.c = xc; - y.e = ye; - return y; - }; - P.pow = function(n) { - var x = this, one = new x.constructor("1"), y = one, isneg = n < 0; - if (n !== ~~n || n < -MAX_POWER || n > MAX_POWER) { - throw Error(INVALID + "exponent"); - } - if (isneg) n = -n; - for (; ; ) { - if (n & 1) y = y.times(x); - n >>= 1; - if (!n) break; - x = x.times(x); - } - return isneg ? one.div(y) : y; - }; - P.prec = function(sd, rm) { - if (sd !== ~~sd || sd < 1 || sd > MAX_DP) { - throw Error(INVALID + "precision"); - } - return round(new this.constructor(this), sd, rm); - }; - P.round = function(dp, rm) { - if (dp === UNDEFINED) dp = 0; - else if (dp !== ~~dp || dp < -MAX_DP || dp > MAX_DP) { - throw Error(INVALID_DP); - } - return round(new this.constructor(this), dp + this.e + 1, rm); - }; - P.sqrt = function() { - var r, c, t, x = this, Big2 = x.constructor, s = x.s, e = x.e, half = new Big2("0.5"); - if (!x.c[0]) return new Big2(x); - if (s < 0) { - throw Error(NAME + "No square root"); - } - s = Math.sqrt(+stringify(x, true, true)); - if (s === 0 || s === 1 / 0) { - c = x.c.join(""); - if (!(c.length + e & 1)) c += "0"; - s = Math.sqrt(c); - e = ((e + 1) / 2 | 0) - (e < 0 || e & 1); - r = new Big2((s == 1 / 0 ? "5e" : (s = s.toExponential()).slice(0, s.indexOf("e") + 1)) + e); - } else { - r = new Big2(s + ""); - } - e = r.e + (Big2.DP += 4); - do { - t = r; - r = half.times(t.plus(x.div(t))); - } while (t.c.slice(0, e).join("") !== r.c.slice(0, e).join("")); - return round(r, (Big2.DP -= 4) + r.e + 1, Big2.RM); - }; - P.times = P.mul = function(y) { - var c, x = this, Big2 = x.constructor, xc = x.c, yc = (y = new Big2(y)).c, a = xc.length, b = yc.length, i = x.e, j = y.e; - y.s = x.s == y.s ? 1 : -1; - if (!xc[0] || !yc[0]) { - y.c = [y.e = 0]; - return y; - } - y.e = i + j; - if (a < b) { - c = xc; - xc = yc; - yc = c; - j = a; - a = b; - b = j; - } - for (c = new Array(j = a + b); j--; ) c[j] = 0; - for (i = b; i--; ) { - b = 0; - for (j = a + i; j > i; ) { - b = c[j] + yc[i] * xc[j - i - 1] + b; - c[j--] = b % 10; - b = b / 10 | 0; - } - c[j] = b; - } - if (b) ++y.e; - else c.shift(); - for (i = c.length; !c[--i]; ) c.pop(); - y.c = c; - return y; - }; - P.toExponential = function(dp, rm) { - var x = this, n = x.c[0]; - if (dp !== UNDEFINED) { - if (dp !== ~~dp || dp < 0 || dp > MAX_DP) { - throw Error(INVALID_DP); - } - x = round(new x.constructor(x), ++dp, rm); - for (; x.c.length < dp; ) x.c.push(0); - } - return stringify(x, true, !!n); - }; - P.toFixed = function(dp, rm) { - var x = this, n = x.c[0]; - if (dp !== UNDEFINED) { - if (dp !== ~~dp || dp < 0 || dp > MAX_DP) { - throw Error(INVALID_DP); - } - x = round(new x.constructor(x), dp + x.e + 1, rm); - for (dp = dp + x.e + 1; x.c.length < dp; ) x.c.push(0); - } - return stringify(x, false, !!n); - }; - P[Symbol.for("nodejs.util.inspect.custom")] = P.toJSON = P.toString = function() { - var x = this, Big2 = x.constructor; - return stringify(x, x.e <= Big2.NE || x.e >= Big2.PE, !!x.c[0]); - }; - P.toNumber = function() { - var n = +stringify(this, true, true); - if (this.constructor.strict === true && !this.eq(n.toString())) { - throw Error(NAME + "Imprecise conversion"); - } - return n; - }; - P.toPrecision = function(sd, rm) { - var x = this, Big2 = x.constructor, n = x.c[0]; - if (sd !== UNDEFINED) { - if (sd !== ~~sd || sd < 1 || sd > MAX_DP) { - throw Error(INVALID + "precision"); - } - x = round(new Big2(x), sd, rm); - for (; x.c.length < sd; ) x.c.push(0); - } - return stringify(x, sd <= x.e || x.e <= Big2.NE || x.e >= Big2.PE, !!n); - }; - P.valueOf = function() { - var x = this, Big2 = x.constructor; - if (Big2.strict === true) { - throw Error(NAME + "valueOf disallowed"); - } - return stringify(x, x.e <= Big2.NE || x.e >= Big2.PE, true); - }; - var Big = _Big_(); - var big_default = Big; - - // ../utils/src/index.ts - var src_exports2 = {}; - __export(src_exports2, { - LsPrefix: () => LsPrefix, - SCHEMA: () => SCHEMA, - base64ToBytes: () => base64ToBytes, - bytesToBase64: () => bytesToBase64, - canSignWithLAK: () => canSignWithLAK, - convertUnit: () => convertUnit, - createDefaultStorage: () => createDefaultStorage, - deepCopy: () => deepCopy, - exp: () => exp, - fromBase58: () => base58_to_binary_default, - fromBase64: () => fromBase64, - fromHex: () => fromHex, - keyFromString: () => keyFromString, - keyToString: () => keyToString, - lsGet: () => lsGet, - lsSet: () => lsSet, - mapAction: () => mapAction, - mapTransaction: () => mapTransaction, - memoryStore: () => memoryStore, - parseJsonFromBytes: () => parseJsonFromBytes, - privateKeyFromRandom: () => privateKeyFromRandom, - publicKeyFromPrivate: () => publicKeyFromPrivate, - serializeSignedTransaction: () => serializeSignedTransaction, - serializeTransaction: () => serializeTransaction, - sha256: () => sha256, - signBytes: () => signBytes, - signHash: () => signHash, - storage: () => storage, - toBase58: () => binary_to_base58_default, - toBase64: () => toBase64, - toHex: () => toHex, - tryParseJson: () => tryParseJson, - txToJson: () => txToJson, - txToJsonStringified: () => txToJsonStringified - }); - - // ../../node_modules/@noble/hashes/esm/_assert.js - function isBytes(a) { - return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array"; - } - __name(isBytes, "isBytes"); - function abytes(b, ...lengths) { - if (!isBytes(b)) - throw new Error("Uint8Array expected"); - if (lengths.length > 0 && !lengths.includes(b.length)) - throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length); - } - __name(abytes, "abytes"); - function aexists(instance, checkFinished = true) { - if (instance.destroyed) - throw new Error("Hash instance has been destroyed"); - if (checkFinished && instance.finished) - throw new Error("Hash#digest() has already been called"); - } - __name(aexists, "aexists"); - function aoutput(out, instance) { - abytes(out); - const min = instance.outputLen; - if (out.length < min) { - throw new Error("digestInto() expects output buffer of length at least " + min); - } - } - __name(aoutput, "aoutput"); - - // ../../node_modules/@noble/hashes/esm/crypto.js - var crypto2 = typeof globalThis === "object" && "crypto" in globalThis ? globalThis.crypto : void 0; - - // ../../node_modules/@noble/hashes/esm/utils.js - function createView(arr) { - return new DataView(arr.buffer, arr.byteOffset, arr.byteLength); - } - __name(createView, "createView"); - function rotr(word, shift) { - return word << 32 - shift | word >>> shift; - } - __name(rotr, "rotr"); - function utf8ToBytes(str) { - if (typeof str !== "string") - throw new Error("utf8ToBytes expected string, got " + typeof str); - return new Uint8Array(new TextEncoder().encode(str)); - } - __name(utf8ToBytes, "utf8ToBytes"); - function toBytes(data) { - if (typeof data === "string") - data = utf8ToBytes(data); - abytes(data); - return data; - } - __name(toBytes, "toBytes"); - var Hash = class { - static { - __name(this, "Hash"); - } - // Safe version that clones internal state - clone() { - return this._cloneInto(); - } - }; - function wrapConstructor(hashCons) { - const hashC = /* @__PURE__ */ __name((msg) => hashCons().update(toBytes(msg)).digest(), "hashC"); - const tmp = hashCons(); - hashC.outputLen = tmp.outputLen; - hashC.blockLen = tmp.blockLen; - hashC.create = () => hashCons(); - return hashC; - } - __name(wrapConstructor, "wrapConstructor"); - function randomBytes(bytesLength = 32) { - if (crypto2 && typeof crypto2.getRandomValues === "function") { - return crypto2.getRandomValues(new Uint8Array(bytesLength)); - } - if (crypto2 && typeof crypto2.randomBytes === "function") { - return crypto2.randomBytes(bytesLength); - } - throw new Error("crypto.getRandomValues must be defined"); - } - __name(randomBytes, "randomBytes"); - - // ../../node_modules/@noble/hashes/esm/_md.js - function setBigUint64(view2, byteOffset, value, isLE) { - if (typeof view2.setBigUint64 === "function") - return view2.setBigUint64(byteOffset, value, isLE); - const _32n2 = BigInt(32); - const _u32_max = BigInt(4294967295); - const wh = Number(value >> _32n2 & _u32_max); - const wl = Number(value & _u32_max); - const h = isLE ? 4 : 0; - const l = isLE ? 0 : 4; - view2.setUint32(byteOffset + h, wh, isLE); - view2.setUint32(byteOffset + l, wl, isLE); - } - __name(setBigUint64, "setBigUint64"); - function Chi(a, b, c) { - return a & b ^ ~a & c; - } - __name(Chi, "Chi"); - function Maj(a, b, c) { - return a & b ^ a & c ^ b & c; - } - __name(Maj, "Maj"); - var HashMD = class extends Hash { - static { - __name(this, "HashMD"); - } - constructor(blockLen, outputLen, padOffset, isLE) { - super(); - this.blockLen = blockLen; - this.outputLen = outputLen; - this.padOffset = padOffset; - this.isLE = isLE; - this.finished = false; - this.length = 0; - this.pos = 0; - this.destroyed = false; - this.buffer = new Uint8Array(blockLen); - this.view = createView(this.buffer); - } - update(data) { - aexists(this); - const { view: view2, buffer, blockLen } = this; - data = toBytes(data); - const len = data.length; - for (let pos = 0; pos < len; ) { - const take = Math.min(blockLen - this.pos, len - pos); - if (take === blockLen) { - const dataView = createView(data); - for (; blockLen <= len - pos; pos += blockLen) - this.process(dataView, pos); - continue; - } - buffer.set(data.subarray(pos, pos + take), this.pos); - this.pos += take; - pos += take; - if (this.pos === blockLen) { - this.process(view2, 0); - this.pos = 0; - } - } - this.length += data.length; - this.roundClean(); - return this; - } - digestInto(out) { - aexists(this); - aoutput(out, this); - this.finished = true; - const { buffer, view: view2, blockLen, isLE } = this; - let { pos } = this; - buffer[pos++] = 128; - this.buffer.subarray(pos).fill(0); - if (this.padOffset > blockLen - pos) { - this.process(view2, 0); - pos = 0; - } - for (let i = pos; i < blockLen; i++) - buffer[i] = 0; - setBigUint64(view2, blockLen - 8, BigInt(this.length * 8), isLE); - this.process(view2, 0); - const oview = createView(out); - const len = this.outputLen; - if (len % 4) - throw new Error("_sha2: outputLen should be aligned to 32bit"); - const outLen = len / 4; - const state2 = this.get(); - if (outLen > state2.length) - throw new Error("_sha2: outputLen bigger than state"); - for (let i = 0; i < outLen; i++) - oview.setUint32(4 * i, state2[i], isLE); - } - digest() { - const { buffer, outputLen } = this; - this.digestInto(buffer); - const res = buffer.slice(0, outputLen); - this.destroy(); - return res; - } - _cloneInto(to) { - to || (to = new this.constructor()); - to.set(...this.get()); - const { blockLen, buffer, length, finished, destroyed, pos } = this; - to.length = length; - to.pos = pos; - to.finished = finished; - to.destroyed = destroyed; - if (length % blockLen) - to.buffer.set(buffer); - return to; - } - }; - - // ../../node_modules/@noble/hashes/esm/_u64.js - var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1); - var _32n = /* @__PURE__ */ BigInt(32); - function fromBig(n, le = false) { - if (le) - return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) }; - return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 }; - } - __name(fromBig, "fromBig"); - function split(lst, le = false) { - let Ah = new Uint32Array(lst.length); - let Al = new Uint32Array(lst.length); - for (let i = 0; i < lst.length; i++) { - const { h, l } = fromBig(lst[i], le); - [Ah[i], Al[i]] = [h, l]; - } - return [Ah, Al]; - } - __name(split, "split"); - var toBig = /* @__PURE__ */ __name((h, l) => BigInt(h >>> 0) << _32n | BigInt(l >>> 0), "toBig"); - var shrSH = /* @__PURE__ */ __name((h, _l, s) => h >>> s, "shrSH"); - var shrSL = /* @__PURE__ */ __name((h, l, s) => h << 32 - s | l >>> s, "shrSL"); - var rotrSH = /* @__PURE__ */ __name((h, l, s) => h >>> s | l << 32 - s, "rotrSH"); - var rotrSL = /* @__PURE__ */ __name((h, l, s) => h << 32 - s | l >>> s, "rotrSL"); - var rotrBH = /* @__PURE__ */ __name((h, l, s) => h << 64 - s | l >>> s - 32, "rotrBH"); - var rotrBL = /* @__PURE__ */ __name((h, l, s) => h >>> s - 32 | l << 64 - s, "rotrBL"); - var rotr32H = /* @__PURE__ */ __name((_h, l) => l, "rotr32H"); - var rotr32L = /* @__PURE__ */ __name((h, _l) => h, "rotr32L"); - var rotlSH = /* @__PURE__ */ __name((h, l, s) => h << s | l >>> 32 - s, "rotlSH"); - var rotlSL = /* @__PURE__ */ __name((h, l, s) => l << s | h >>> 32 - s, "rotlSL"); - var rotlBH = /* @__PURE__ */ __name((h, l, s) => l << s - 32 | h >>> 64 - s, "rotlBH"); - var rotlBL = /* @__PURE__ */ __name((h, l, s) => h << s - 32 | l >>> 64 - s, "rotlBL"); - function add(Ah, Al, Bh, Bl) { - const l = (Al >>> 0) + (Bl >>> 0); - return { h: Ah + Bh + (l / 2 ** 32 | 0) | 0, l: l | 0 }; - } - __name(add, "add"); - var add3L = /* @__PURE__ */ __name((Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0), "add3L"); - var add3H = /* @__PURE__ */ __name((low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0, "add3H"); - var add4L = /* @__PURE__ */ __name((Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0), "add4L"); - var add4H = /* @__PURE__ */ __name((low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0, "add4H"); - var add5L = /* @__PURE__ */ __name((Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0), "add5L"); - var add5H = /* @__PURE__ */ __name((low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0, "add5H"); - var u64 = { - fromBig, - split, - toBig, - shrSH, - shrSL, - rotrSH, - rotrSL, - rotrBH, - rotrBL, - rotr32H, - rotr32L, - rotlSH, - rotlSL, - rotlBH, - rotlBL, - add, - add3L, - add3H, - add4L, - add4H, - add5H, - add5L - }; - var u64_default = u64; - - // ../../node_modules/@noble/hashes/esm/sha512.js - var [SHA512_Kh, SHA512_Kl] = /* @__PURE__ */ (() => u64_default.split([ - "0x428a2f98d728ae22", - "0x7137449123ef65cd", - "0xb5c0fbcfec4d3b2f", - "0xe9b5dba58189dbbc", - "0x3956c25bf348b538", - "0x59f111f1b605d019", - "0x923f82a4af194f9b", - "0xab1c5ed5da6d8118", - "0xd807aa98a3030242", - "0x12835b0145706fbe", - "0x243185be4ee4b28c", - "0x550c7dc3d5ffb4e2", - "0x72be5d74f27b896f", - "0x80deb1fe3b1696b1", - "0x9bdc06a725c71235", - "0xc19bf174cf692694", - "0xe49b69c19ef14ad2", - "0xefbe4786384f25e3", - "0x0fc19dc68b8cd5b5", - "0x240ca1cc77ac9c65", - "0x2de92c6f592b0275", - "0x4a7484aa6ea6e483", - "0x5cb0a9dcbd41fbd4", - "0x76f988da831153b5", - "0x983e5152ee66dfab", - "0xa831c66d2db43210", - "0xb00327c898fb213f", - "0xbf597fc7beef0ee4", - "0xc6e00bf33da88fc2", - "0xd5a79147930aa725", - "0x06ca6351e003826f", - "0x142929670a0e6e70", - "0x27b70a8546d22ffc", - "0x2e1b21385c26c926", - "0x4d2c6dfc5ac42aed", - "0x53380d139d95b3df", - "0x650a73548baf63de", - "0x766a0abb3c77b2a8", - "0x81c2c92e47edaee6", - "0x92722c851482353b", - "0xa2bfe8a14cf10364", - "0xa81a664bbc423001", - "0xc24b8b70d0f89791", - "0xc76c51a30654be30", - "0xd192e819d6ef5218", - "0xd69906245565a910", - "0xf40e35855771202a", - "0x106aa07032bbd1b8", - "0x19a4c116b8d2d0c8", - "0x1e376c085141ab53", - "0x2748774cdf8eeb99", - "0x34b0bcb5e19b48a8", - "0x391c0cb3c5c95a63", - "0x4ed8aa4ae3418acb", - "0x5b9cca4f7763e373", - "0x682e6ff3d6b2b8a3", - "0x748f82ee5defb2fc", - "0x78a5636f43172f60", - "0x84c87814a1f0ab72", - "0x8cc702081a6439ec", - "0x90befffa23631e28", - "0xa4506cebde82bde9", - "0xbef9a3f7b2c67915", - "0xc67178f2e372532b", - "0xca273eceea26619c", - "0xd186b8c721c0c207", - "0xeada7dd6cde0eb1e", - "0xf57d4f7fee6ed178", - "0x06f067aa72176fba", - "0x0a637dc5a2c898a6", - "0x113f9804bef90dae", - "0x1b710b35131c471b", - "0x28db77f523047d84", - "0x32caab7b40c72493", - "0x3c9ebe0a15c9bebc", - "0x431d67c49c100d4c", - "0x4cc5d4becb3e42b6", - "0x597f299cfc657e2a", - "0x5fcb6fab3ad6faec", - "0x6c44198c4a475817" - ].map((n) => BigInt(n))))(); - var SHA512_W_H = /* @__PURE__ */ new Uint32Array(80); - var SHA512_W_L = /* @__PURE__ */ new Uint32Array(80); - var SHA512 = class extends HashMD { - static { - __name(this, "SHA512"); - } - constructor() { - super(128, 64, 16, false); - this.Ah = 1779033703 | 0; - this.Al = 4089235720 | 0; - this.Bh = 3144134277 | 0; - this.Bl = 2227873595 | 0; - this.Ch = 1013904242 | 0; - this.Cl = 4271175723 | 0; - this.Dh = 2773480762 | 0; - this.Dl = 1595750129 | 0; - this.Eh = 1359893119 | 0; - this.El = 2917565137 | 0; - this.Fh = 2600822924 | 0; - this.Fl = 725511199 | 0; - this.Gh = 528734635 | 0; - this.Gl = 4215389547 | 0; - this.Hh = 1541459225 | 0; - this.Hl = 327033209 | 0; - } - // prettier-ignore - get() { - const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; - return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl]; - } - // prettier-ignore - set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) { - this.Ah = Ah | 0; - this.Al = Al | 0; - this.Bh = Bh | 0; - this.Bl = Bl | 0; - this.Ch = Ch | 0; - this.Cl = Cl | 0; - this.Dh = Dh | 0; - this.Dl = Dl | 0; - this.Eh = Eh | 0; - this.El = El | 0; - this.Fh = Fh | 0; - this.Fl = Fl | 0; - this.Gh = Gh | 0; - this.Gl = Gl | 0; - this.Hh = Hh | 0; - this.Hl = Hl | 0; - } - process(view2, offset) { - for (let i = 0; i < 16; i++, offset += 4) { - SHA512_W_H[i] = view2.getUint32(offset); - SHA512_W_L[i] = view2.getUint32(offset += 4); - } - for (let i = 16; i < 80; i++) { - const W15h = SHA512_W_H[i - 15] | 0; - const W15l = SHA512_W_L[i - 15] | 0; - const s0h = u64_default.rotrSH(W15h, W15l, 1) ^ u64_default.rotrSH(W15h, W15l, 8) ^ u64_default.shrSH(W15h, W15l, 7); - const s0l = u64_default.rotrSL(W15h, W15l, 1) ^ u64_default.rotrSL(W15h, W15l, 8) ^ u64_default.shrSL(W15h, W15l, 7); - const W2h = SHA512_W_H[i - 2] | 0; - const W2l = SHA512_W_L[i - 2] | 0; - const s1h = u64_default.rotrSH(W2h, W2l, 19) ^ u64_default.rotrBH(W2h, W2l, 61) ^ u64_default.shrSH(W2h, W2l, 6); - const s1l = u64_default.rotrSL(W2h, W2l, 19) ^ u64_default.rotrBL(W2h, W2l, 61) ^ u64_default.shrSL(W2h, W2l, 6); - const SUMl = u64_default.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]); - const SUMh = u64_default.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]); - SHA512_W_H[i] = SUMh | 0; - SHA512_W_L[i] = SUMl | 0; - } - let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; - for (let i = 0; i < 80; i++) { - const sigma1h = u64_default.rotrSH(Eh, El, 14) ^ u64_default.rotrSH(Eh, El, 18) ^ u64_default.rotrBH(Eh, El, 41); - const sigma1l = u64_default.rotrSL(Eh, El, 14) ^ u64_default.rotrSL(Eh, El, 18) ^ u64_default.rotrBL(Eh, El, 41); - const CHIh = Eh & Fh ^ ~Eh & Gh; - const CHIl = El & Fl ^ ~El & Gl; - const T1ll = u64_default.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]); - const T1h = u64_default.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]); - const T1l = T1ll | 0; - const sigma0h = u64_default.rotrSH(Ah, Al, 28) ^ u64_default.rotrBH(Ah, Al, 34) ^ u64_default.rotrBH(Ah, Al, 39); - const sigma0l = u64_default.rotrSL(Ah, Al, 28) ^ u64_default.rotrBL(Ah, Al, 34) ^ u64_default.rotrBL(Ah, Al, 39); - const MAJh = Ah & Bh ^ Ah & Ch ^ Bh & Ch; - const MAJl = Al & Bl ^ Al & Cl ^ Bl & Cl; - Hh = Gh | 0; - Hl = Gl | 0; - Gh = Fh | 0; - Gl = Fl | 0; - Fh = Eh | 0; - Fl = El | 0; - ({ h: Eh, l: El } = u64_default.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0)); - Dh = Ch | 0; - Dl = Cl | 0; - Ch = Bh | 0; - Cl = Bl | 0; - Bh = Ah | 0; - Bl = Al | 0; - const All = u64_default.add3L(T1l, sigma0l, MAJl); - Ah = u64_default.add3H(All, T1h, sigma0h, MAJh); - Al = All | 0; - } - ({ h: Ah, l: Al } = u64_default.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0)); - ({ h: Bh, l: Bl } = u64_default.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0)); - ({ h: Ch, l: Cl } = u64_default.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0)); - ({ h: Dh, l: Dl } = u64_default.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0)); - ({ h: Eh, l: El } = u64_default.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0)); - ({ h: Fh, l: Fl } = u64_default.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0)); - ({ h: Gh, l: Gl } = u64_default.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0)); - ({ h: Hh, l: Hl } = u64_default.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0)); - this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl); - } - roundClean() { - SHA512_W_H.fill(0); - SHA512_W_L.fill(0); - } - destroy() { - this.buffer.fill(0); - this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - } - }; - var sha512 = /* @__PURE__ */ wrapConstructor(() => new SHA512()); - - // ../../node_modules/@noble/curves/esm/abstract/utils.js - var _0n = /* @__PURE__ */ BigInt(0); - var _1n = /* @__PURE__ */ BigInt(1); - var _2n = /* @__PURE__ */ BigInt(2); - function isBytes2(a) { - return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array"; - } - __name(isBytes2, "isBytes"); - function abytes2(item) { - if (!isBytes2(item)) - throw new Error("Uint8Array expected"); - } - __name(abytes2, "abytes"); - function abool(title, value) { - if (typeof value !== "boolean") - throw new Error(title + " boolean expected, got " + value); - } - __name(abool, "abool"); - var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0")); - function bytesToHex(bytes) { - abytes2(bytes); - let hex = ""; - for (let i = 0; i < bytes.length; i++) { - hex += hexes[bytes[i]]; - } - return hex; - } - __name(bytesToHex, "bytesToHex"); - function hexToNumber(hex) { - if (typeof hex !== "string") - throw new Error("hex string expected, got " + typeof hex); - return hex === "" ? _0n : BigInt("0x" + hex); - } - __name(hexToNumber, "hexToNumber"); - var asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 }; - function asciiToBase16(ch) { - if (ch >= asciis._0 && ch <= asciis._9) - return ch - asciis._0; - if (ch >= asciis.A && ch <= asciis.F) - return ch - (asciis.A - 10); - if (ch >= asciis.a && ch <= asciis.f) - return ch - (asciis.a - 10); - return; - } - __name(asciiToBase16, "asciiToBase16"); - function hexToBytes(hex) { - if (typeof hex !== "string") - throw new Error("hex string expected, got " + typeof hex); - const hl = hex.length; - const al = hl / 2; - if (hl % 2) - throw new Error("hex string expected, got unpadded hex of length " + hl); - const array = new Uint8Array(al); - for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) { - const n1 = asciiToBase16(hex.charCodeAt(hi)); - const n2 = asciiToBase16(hex.charCodeAt(hi + 1)); - if (n1 === void 0 || n2 === void 0) { - const char = hex[hi] + hex[hi + 1]; - throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi); - } - array[ai] = n1 * 16 + n2; - } - return array; - } - __name(hexToBytes, "hexToBytes"); - function bytesToNumberBE(bytes) { - return hexToNumber(bytesToHex(bytes)); - } - __name(bytesToNumberBE, "bytesToNumberBE"); - function bytesToNumberLE(bytes) { - abytes2(bytes); - return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse())); - } - __name(bytesToNumberLE, "bytesToNumberLE"); - function numberToBytesBE(n, len) { - return hexToBytes(n.toString(16).padStart(len * 2, "0")); - } - __name(numberToBytesBE, "numberToBytesBE"); - function numberToBytesLE(n, len) { - return numberToBytesBE(n, len).reverse(); - } - __name(numberToBytesLE, "numberToBytesLE"); - function ensureBytes(title, hex, expectedLength) { - let res; - if (typeof hex === "string") { - try { - res = hexToBytes(hex); - } catch (e) { - throw new Error(title + " must be hex string or Uint8Array, cause: " + e); - } - } else if (isBytes2(hex)) { - res = Uint8Array.from(hex); - } else { - throw new Error(title + " must be hex string or Uint8Array"); - } - const len = res.length; - if (typeof expectedLength === "number" && len !== expectedLength) - throw new Error(title + " of length " + expectedLength + " expected, got " + len); - return res; - } - __name(ensureBytes, "ensureBytes"); - function concatBytes(...arrays) { - let sum = 0; - for (let i = 0; i < arrays.length; i++) { - const a = arrays[i]; - abytes2(a); - sum += a.length; - } - const res = new Uint8Array(sum); - for (let i = 0, pad = 0; i < arrays.length; i++) { - const a = arrays[i]; - res.set(a, pad); - pad += a.length; - } - return res; - } - __name(concatBytes, "concatBytes"); - var isPosBig = /* @__PURE__ */ __name((n) => typeof n === "bigint" && _0n <= n, "isPosBig"); - function inRange(n, min, max) { - return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max; - } - __name(inRange, "inRange"); - function aInRange(title, n, min, max) { - if (!inRange(n, min, max)) - throw new Error("expected valid " + title + ": " + min + " <= n < " + max + ", got " + n); - } - __name(aInRange, "aInRange"); - function bitLen(n) { - let len; - for (len = 0; n > _0n; n >>= _1n, len += 1) - ; - return len; - } - __name(bitLen, "bitLen"); - var bitMask = /* @__PURE__ */ __name((n) => (_2n << BigInt(n - 1)) - _1n, "bitMask"); - var validatorFns = { - bigint: /* @__PURE__ */ __name((val) => typeof val === "bigint", "bigint"), - function: /* @__PURE__ */ __name((val) => typeof val === "function", "function"), - boolean: /* @__PURE__ */ __name((val) => typeof val === "boolean", "boolean"), - string: /* @__PURE__ */ __name((val) => typeof val === "string", "string"), - stringOrUint8Array: /* @__PURE__ */ __name((val) => typeof val === "string" || isBytes2(val), "stringOrUint8Array"), - isSafeInteger: /* @__PURE__ */ __name((val) => Number.isSafeInteger(val), "isSafeInteger"), - array: /* @__PURE__ */ __name((val) => Array.isArray(val), "array"), - field: /* @__PURE__ */ __name((val, object) => object.Fp.isValid(val), "field"), - hash: /* @__PURE__ */ __name((val) => typeof val === "function" && Number.isSafeInteger(val.outputLen), "hash") - }; - function validateObject(object, validators, optValidators = {}) { - const checkField = /* @__PURE__ */ __name((fieldName, type, isOptional) => { - const checkVal = validatorFns[type]; - if (typeof checkVal !== "function") - throw new Error("invalid validator function"); - const val = object[fieldName]; - if (isOptional && val === void 0) - return; - if (!checkVal(val, object)) { - throw new Error("param " + String(fieldName) + " is invalid. Expected " + type + ", got " + val); - } - }, "checkField"); - for (const [fieldName, type] of Object.entries(validators)) - checkField(fieldName, type, false); - for (const [fieldName, type] of Object.entries(optValidators)) - checkField(fieldName, type, true); - return object; - } - __name(validateObject, "validateObject"); - function memoized(fn) { - const map = /* @__PURE__ */ new WeakMap(); - return (arg, ...args) => { - const val = map.get(arg); - if (val !== void 0) - return val; - const computed = fn(arg, ...args); - map.set(arg, computed); - return computed; - }; - } - __name(memoized, "memoized"); - - // ../../node_modules/@noble/curves/esm/abstract/modular.js - var _0n2 = BigInt(0); - var _1n2 = BigInt(1); - var _2n2 = /* @__PURE__ */ BigInt(2); - var _3n = /* @__PURE__ */ BigInt(3); - var _4n = /* @__PURE__ */ BigInt(4); - var _5n = /* @__PURE__ */ BigInt(5); - var _8n = /* @__PURE__ */ BigInt(8); - var _9n = /* @__PURE__ */ BigInt(9); - var _16n = /* @__PURE__ */ BigInt(16); - function mod(a, b) { - const result = a % b; - return result >= _0n2 ? result : b + result; - } - __name(mod, "mod"); - function pow(num, power, modulo) { - if (power < _0n2) - throw new Error("invalid exponent, negatives unsupported"); - if (modulo <= _0n2) - throw new Error("invalid modulus"); - if (modulo === _1n2) - return _0n2; - let res = _1n2; - while (power > _0n2) { - if (power & _1n2) - res = res * num % modulo; - num = num * num % modulo; - power >>= _1n2; - } - return res; - } - __name(pow, "pow"); - function pow2(x, power, modulo) { - let res = x; - while (power-- > _0n2) { - res *= res; - res %= modulo; - } - return res; - } - __name(pow2, "pow2"); - function invert(number, modulo) { - if (number === _0n2) - throw new Error("invert: expected non-zero number"); - if (modulo <= _0n2) - throw new Error("invert: expected positive modulus, got " + modulo); - let a = mod(number, modulo); - let b = modulo; - let x = _0n2, y = _1n2, u = _1n2, v = _0n2; - while (a !== _0n2) { - const q = b / a; - const r = b % a; - const m = x - u * q; - const n = y - v * q; - b = a, a = r, x = u, y = v, u = m, v = n; - } - const gcd = b; - if (gcd !== _1n2) - throw new Error("invert: does not exist"); - return mod(x, modulo); - } - __name(invert, "invert"); - function tonelliShanks(P2) { - const legendreC = (P2 - _1n2) / _2n2; - let Q, S, Z; - for (Q = P2 - _1n2, S = 0; Q % _2n2 === _0n2; Q /= _2n2, S++) - ; - for (Z = _2n2; Z < P2 && pow(Z, legendreC, P2) !== P2 - _1n2; Z++) { - if (Z > 1e3) - throw new Error("Cannot find square root: likely non-prime P"); - } - if (S === 1) { - const p1div4 = (P2 + _1n2) / _4n; - return /* @__PURE__ */ __name(function tonelliFast(Fp2, n) { - const root = Fp2.pow(n, p1div4); - if (!Fp2.eql(Fp2.sqr(root), n)) - throw new Error("Cannot find square root"); - return root; - }, "tonelliFast"); - } - const Q1div2 = (Q + _1n2) / _2n2; - return /* @__PURE__ */ __name(function tonelliSlow(Fp2, n) { - if (Fp2.pow(n, legendreC) === Fp2.neg(Fp2.ONE)) - throw new Error("Cannot find square root"); - let r = S; - let g = Fp2.pow(Fp2.mul(Fp2.ONE, Z), Q); - let x = Fp2.pow(n, Q1div2); - let b = Fp2.pow(n, Q); - while (!Fp2.eql(b, Fp2.ONE)) { - if (Fp2.eql(b, Fp2.ZERO)) - return Fp2.ZERO; - let m = 1; - for (let t2 = Fp2.sqr(b); m < r; m++) { - if (Fp2.eql(t2, Fp2.ONE)) - break; - t2 = Fp2.sqr(t2); - } - const ge = Fp2.pow(g, _1n2 << BigInt(r - m - 1)); - g = Fp2.sqr(ge); - x = Fp2.mul(x, ge); - b = Fp2.mul(b, g); - r = m; - } - return x; - }, "tonelliSlow"); - } - __name(tonelliShanks, "tonelliShanks"); - function FpSqrt(P2) { - if (P2 % _4n === _3n) { - const p1div4 = (P2 + _1n2) / _4n; - return /* @__PURE__ */ __name(function sqrt3mod4(Fp2, n) { - const root = Fp2.pow(n, p1div4); - if (!Fp2.eql(Fp2.sqr(root), n)) - throw new Error("Cannot find square root"); - return root; - }, "sqrt3mod4"); - } - if (P2 % _8n === _5n) { - const c1 = (P2 - _5n) / _8n; - return /* @__PURE__ */ __name(function sqrt5mod8(Fp2, n) { - const n2 = Fp2.mul(n, _2n2); - const v = Fp2.pow(n2, c1); - const nv = Fp2.mul(n, v); - const i = Fp2.mul(Fp2.mul(nv, _2n2), v); - const root = Fp2.mul(nv, Fp2.sub(i, Fp2.ONE)); - if (!Fp2.eql(Fp2.sqr(root), n)) - throw new Error("Cannot find square root"); - return root; - }, "sqrt5mod8"); - } - if (P2 % _16n === _9n) { - } - return tonelliShanks(P2); - } - __name(FpSqrt, "FpSqrt"); - var isNegativeLE = /* @__PURE__ */ __name((num, modulo) => (mod(num, modulo) & _1n2) === _1n2, "isNegativeLE"); - var FIELD_FIELDS = [ - "create", - "isValid", - "is0", - "neg", - "inv", - "sqrt", - "sqr", - "eql", - "add", - "sub", - "mul", - "pow", - "div", - "addN", - "subN", - "mulN", - "sqrN" - ]; - function validateField(field) { - const initial = { - ORDER: "bigint", - MASK: "bigint", - BYTES: "isSafeInteger", - BITS: "isSafeInteger" - }; - const opts = FIELD_FIELDS.reduce((map, val) => { - map[val] = "function"; - return map; - }, initial); - return validateObject(field, opts); - } - __name(validateField, "validateField"); - function FpPow(f, num, power) { - if (power < _0n2) - throw new Error("invalid exponent, negatives unsupported"); - if (power === _0n2) - return f.ONE; - if (power === _1n2) - return num; - let p = f.ONE; - let d = num; - while (power > _0n2) { - if (power & _1n2) - p = f.mul(p, d); - d = f.sqr(d); - power >>= _1n2; - } - return p; - } - __name(FpPow, "FpPow"); - function FpInvertBatch(f, nums) { - const tmp = new Array(nums.length); - const lastMultiplied = nums.reduce((acc, num, i) => { - if (f.is0(num)) - return acc; - tmp[i] = acc; - return f.mul(acc, num); - }, f.ONE); - const inverted = f.inv(lastMultiplied); - nums.reduceRight((acc, num, i) => { - if (f.is0(num)) - return acc; - tmp[i] = f.mul(acc, tmp[i]); - return f.mul(acc, num); - }, inverted); - return tmp; - } - __name(FpInvertBatch, "FpInvertBatch"); - function nLength(n, nBitLength) { - const _nBitLength = nBitLength !== void 0 ? nBitLength : n.toString(2).length; - const nByteLength = Math.ceil(_nBitLength / 8); - return { nBitLength: _nBitLength, nByteLength }; - } - __name(nLength, "nLength"); - function Field(ORDER, bitLen2, isLE = false, redef = {}) { - if (ORDER <= _0n2) - throw new Error("invalid field: expected ORDER > 0, got " + ORDER); - const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen2); - if (BYTES > 2048) - throw new Error("invalid field: expected ORDER of <= 2048 bytes"); - let sqrtP; - const f = Object.freeze({ - ORDER, - isLE, - BITS, - BYTES, - MASK: bitMask(BITS), - ZERO: _0n2, - ONE: _1n2, - create: /* @__PURE__ */ __name((num) => mod(num, ORDER), "create"), - isValid: /* @__PURE__ */ __name((num) => { - if (typeof num !== "bigint") - throw new Error("invalid field element: expected bigint, got " + typeof num); - return _0n2 <= num && num < ORDER; - }, "isValid"), - is0: /* @__PURE__ */ __name((num) => num === _0n2, "is0"), - isOdd: /* @__PURE__ */ __name((num) => (num & _1n2) === _1n2, "isOdd"), - neg: /* @__PURE__ */ __name((num) => mod(-num, ORDER), "neg"), - eql: /* @__PURE__ */ __name((lhs, rhs) => lhs === rhs, "eql"), - sqr: /* @__PURE__ */ __name((num) => mod(num * num, ORDER), "sqr"), - add: /* @__PURE__ */ __name((lhs, rhs) => mod(lhs + rhs, ORDER), "add"), - sub: /* @__PURE__ */ __name((lhs, rhs) => mod(lhs - rhs, ORDER), "sub"), - mul: /* @__PURE__ */ __name((lhs, rhs) => mod(lhs * rhs, ORDER), "mul"), - pow: /* @__PURE__ */ __name((num, power) => FpPow(f, num, power), "pow"), - div: /* @__PURE__ */ __name((lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER), "div"), - // Same as above, but doesn't normalize - sqrN: /* @__PURE__ */ __name((num) => num * num, "sqrN"), - addN: /* @__PURE__ */ __name((lhs, rhs) => lhs + rhs, "addN"), - subN: /* @__PURE__ */ __name((lhs, rhs) => lhs - rhs, "subN"), - mulN: /* @__PURE__ */ __name((lhs, rhs) => lhs * rhs, "mulN"), - inv: /* @__PURE__ */ __name((num) => invert(num, ORDER), "inv"), - sqrt: redef.sqrt || ((n) => { - if (!sqrtP) - sqrtP = FpSqrt(ORDER); - return sqrtP(f, n); - }), - invertBatch: /* @__PURE__ */ __name((lst) => FpInvertBatch(f, lst), "invertBatch"), - // TODO: do we really need constant cmov? - // We don't have const-time bigints anyway, so probably will be not very useful - cmov: /* @__PURE__ */ __name((a, b, c) => c ? b : a, "cmov"), - toBytes: /* @__PURE__ */ __name((num) => isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES), "toBytes"), - fromBytes: /* @__PURE__ */ __name((bytes) => { - if (bytes.length !== BYTES) - throw new Error("Field.fromBytes: expected " + BYTES + " bytes, got " + bytes.length); - return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes); - }, "fromBytes") - }); - return Object.freeze(f); - } - __name(Field, "Field"); - - // ../../node_modules/@noble/curves/esm/abstract/curve.js - var _0n3 = BigInt(0); - var _1n3 = BigInt(1); - function constTimeNegate(condition, item) { - const neg = item.negate(); - return condition ? neg : item; - } - __name(constTimeNegate, "constTimeNegate"); - function validateW(W, bits) { - if (!Number.isSafeInteger(W) || W <= 0 || W > bits) - throw new Error("invalid window size, expected [1.." + bits + "], got W=" + W); - } - __name(validateW, "validateW"); - function calcWOpts(W, bits) { - validateW(W, bits); - const windows = Math.ceil(bits / W) + 1; - const windowSize = 2 ** (W - 1); - return { windows, windowSize }; - } - __name(calcWOpts, "calcWOpts"); - function validateMSMPoints(points, c) { - if (!Array.isArray(points)) - throw new Error("array expected"); - points.forEach((p, i) => { - if (!(p instanceof c)) - throw new Error("invalid point at index " + i); - }); - } - __name(validateMSMPoints, "validateMSMPoints"); - function validateMSMScalars(scalars, field) { - if (!Array.isArray(scalars)) - throw new Error("array of scalars expected"); - scalars.forEach((s, i) => { - if (!field.isValid(s)) - throw new Error("invalid scalar at index " + i); - }); - } - __name(validateMSMScalars, "validateMSMScalars"); - var pointPrecomputes = /* @__PURE__ */ new WeakMap(); - var pointWindowSizes = /* @__PURE__ */ new WeakMap(); - function getW(P2) { - return pointWindowSizes.get(P2) || 1; - } - __name(getW, "getW"); - function wNAF(c, bits) { - return { - constTimeNegate, - hasPrecomputes(elm) { - return getW(elm) !== 1; - }, - // non-const time multiplication ladder - unsafeLadder(elm, n, p = c.ZERO) { - let d = elm; - while (n > _0n3) { - if (n & _1n3) - p = p.add(d); - d = d.double(); - n >>= _1n3; - } - return p; - }, - /** - * Creates a wNAF precomputation window. Used for caching. - * Default window size is set by `utils.precompute()` and is equal to 8. - * Number of precomputed points depends on the curve size: - * 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where: - * - 𝑊 is the window size - * - 𝑛 is the bitlength of the curve order. - * For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224. - * @param elm Point instance - * @param W window size - * @returns precomputed point tables flattened to a single array - */ - precomputeWindow(elm, W) { - const { windows, windowSize } = calcWOpts(W, bits); - const points = []; - let p = elm; - let base = p; - for (let window2 = 0; window2 < windows; window2++) { - base = p; - points.push(base); - for (let i = 1; i < windowSize; i++) { - base = base.add(p); - points.push(base); - } - p = base.double(); - } - return points; - }, - /** - * Implements ec multiplication using precomputed tables and w-ary non-adjacent form. - * @param W window size - * @param precomputes precomputed tables - * @param n scalar (we don't check here, but should be less than curve order) - * @returns real and fake (for const-time) points - */ - wNAF(W, precomputes, n) { - const { windows, windowSize } = calcWOpts(W, bits); - let p = c.ZERO; - let f = c.BASE; - const mask = BigInt(2 ** W - 1); - const maxNumber = 2 ** W; - const shiftBy = BigInt(W); - for (let window2 = 0; window2 < windows; window2++) { - const offset = window2 * windowSize; - let wbits = Number(n & mask); - n >>= shiftBy; - if (wbits > windowSize) { - wbits -= maxNumber; - n += _1n3; - } - const offset1 = offset; - const offset2 = offset + Math.abs(wbits) - 1; - const cond1 = window2 % 2 !== 0; - const cond2 = wbits < 0; - if (wbits === 0) { - f = f.add(constTimeNegate(cond1, precomputes[offset1])); - } else { - p = p.add(constTimeNegate(cond2, precomputes[offset2])); - } - } - return { p, f }; - }, - /** - * Implements ec unsafe (non const-time) multiplication using precomputed tables and w-ary non-adjacent form. - * @param W window size - * @param precomputes precomputed tables - * @param n scalar (we don't check here, but should be less than curve order) - * @param acc accumulator point to add result of multiplication - * @returns point - */ - wNAFUnsafe(W, precomputes, n, acc = c.ZERO) { - const { windows, windowSize } = calcWOpts(W, bits); - const mask = BigInt(2 ** W - 1); - const maxNumber = 2 ** W; - const shiftBy = BigInt(W); - for (let window2 = 0; window2 < windows; window2++) { - const offset = window2 * windowSize; - if (n === _0n3) - break; - let wbits = Number(n & mask); - n >>= shiftBy; - if (wbits > windowSize) { - wbits -= maxNumber; - n += _1n3; - } - if (wbits === 0) - continue; - let curr = precomputes[offset + Math.abs(wbits) - 1]; - if (wbits < 0) - curr = curr.negate(); - acc = acc.add(curr); - } - return acc; - }, - getPrecomputes(W, P2, transform) { - let comp = pointPrecomputes.get(P2); - if (!comp) { - comp = this.precomputeWindow(P2, W); - if (W !== 1) - pointPrecomputes.set(P2, transform(comp)); - } - return comp; - }, - wNAFCached(P2, n, transform) { - const W = getW(P2); - return this.wNAF(W, this.getPrecomputes(W, P2, transform), n); - }, - wNAFCachedUnsafe(P2, n, transform, prev) { - const W = getW(P2); - if (W === 1) - return this.unsafeLadder(P2, n, prev); - return this.wNAFUnsafe(W, this.getPrecomputes(W, P2, transform), n, prev); - }, - // We calculate precomputes for elliptic curve point multiplication - // using windowed method. This specifies window size and - // stores precomputed values. Usually only base point would be precomputed. - setWindowSize(P2, W) { - validateW(W, bits); - pointWindowSizes.set(P2, W); - pointPrecomputes.delete(P2); - } - }; - } - __name(wNAF, "wNAF"); - function pippenger(c, fieldN, points, scalars) { - validateMSMPoints(points, c); - validateMSMScalars(scalars, fieldN); - if (points.length !== scalars.length) - throw new Error("arrays of points and scalars must have equal length"); - const zero = c.ZERO; - const wbits = bitLen(BigInt(points.length)); - const windowSize = wbits > 12 ? wbits - 3 : wbits > 4 ? wbits - 2 : wbits ? 2 : 1; - const MASK = (1 << windowSize) - 1; - const buckets = new Array(MASK + 1).fill(zero); - const lastBits = Math.floor((fieldN.BITS - 1) / windowSize) * windowSize; - let sum = zero; - for (let i = lastBits; i >= 0; i -= windowSize) { - buckets.fill(zero); - for (let j = 0; j < scalars.length; j++) { - const scalar = scalars[j]; - const wbits2 = Number(scalar >> BigInt(i) & BigInt(MASK)); - buckets[wbits2] = buckets[wbits2].add(points[j]); - } - let resI = zero; - for (let j = buckets.length - 1, sumI = zero; j > 0; j--) { - sumI = sumI.add(buckets[j]); - resI = resI.add(sumI); - } - sum = sum.add(resI); - if (i !== 0) - for (let j = 0; j < windowSize; j++) - sum = sum.double(); - } - return sum; - } - __name(pippenger, "pippenger"); - function validateBasic(curve) { - validateField(curve.Fp); - validateObject(curve, { - n: "bigint", - h: "bigint", - Gx: "field", - Gy: "field" - }, { - nBitLength: "isSafeInteger", - nByteLength: "isSafeInteger" - }); - return Object.freeze({ - ...nLength(curve.n, curve.nBitLength), - ...curve, - ...{ p: curve.Fp.ORDER } - }); - } - __name(validateBasic, "validateBasic"); - - // ../../node_modules/@noble/curves/esm/abstract/edwards.js - var _0n4 = BigInt(0); - var _1n4 = BigInt(1); - var _2n3 = BigInt(2); - var _8n2 = BigInt(8); - var VERIFY_DEFAULT = { zip215: true }; - function validateOpts(curve) { - const opts = validateBasic(curve); - validateObject(curve, { - hash: "function", - a: "bigint", - d: "bigint", - randomBytes: "function" - }, { - adjustScalarBytes: "function", - domain: "function", - uvRatio: "function", - mapToCurve: "function" - }); - return Object.freeze({ ...opts }); - } - __name(validateOpts, "validateOpts"); - function twistedEdwards(curveDef) { - const CURVE = validateOpts(curveDef); - const { Fp: Fp2, n: CURVE_ORDER, prehash, hash: cHash, randomBytes: randomBytes2, nByteLength, h: cofactor } = CURVE; - const MASK = _2n3 << BigInt(nByteLength * 8) - _1n4; - const modP = Fp2.create; - const Fn = Field(CURVE.n, CURVE.nBitLength); - const uvRatio2 = CURVE.uvRatio || ((u, v) => { - try { - return { isValid: true, value: Fp2.sqrt(u * Fp2.inv(v)) }; - } catch (e) { - return { isValid: false, value: _0n4 }; - } - }); - const adjustScalarBytes2 = CURVE.adjustScalarBytes || ((bytes) => bytes); - const domain = CURVE.domain || ((data, ctx, phflag) => { - abool("phflag", phflag); - if (ctx.length || phflag) - throw new Error("Contexts/pre-hash are not supported"); - return data; - }); - function aCoordinate(title, n) { - aInRange("coordinate " + title, n, _0n4, MASK); - } - __name(aCoordinate, "aCoordinate"); - function assertPoint(other) { - if (!(other instanceof Point)) - throw new Error("ExtendedPoint expected"); - } - __name(assertPoint, "assertPoint"); - const toAffineMemo = memoized((p, iz) => { - const { ex: x, ey: y, ez: z } = p; - const is0 = p.is0(); - if (iz == null) - iz = is0 ? _8n2 : Fp2.inv(z); - const ax = modP(x * iz); - const ay = modP(y * iz); - const zz = modP(z * iz); - if (is0) - return { x: _0n4, y: _1n4 }; - if (zz !== _1n4) - throw new Error("invZ was invalid"); - return { x: ax, y: ay }; - }); - const assertValidMemo = memoized((p) => { - const { a, d } = CURVE; - if (p.is0()) - throw new Error("bad point: ZERO"); - const { ex: X, ey: Y, ez: Z, et: T } = p; - const X2 = modP(X * X); - const Y2 = modP(Y * Y); - const Z2 = modP(Z * Z); - const Z4 = modP(Z2 * Z2); - const aX2 = modP(X2 * a); - const left = modP(Z2 * modP(aX2 + Y2)); - const right = modP(Z4 + modP(d * modP(X2 * Y2))); - if (left !== right) - throw new Error("bad point: equation left != right (1)"); - const XY = modP(X * Y); - const ZT = modP(Z * T); - if (XY !== ZT) - throw new Error("bad point: equation left != right (2)"); - return true; - }); - class Point { - static { - __name(this, "Point"); - } - constructor(ex, ey, ez, et) { - this.ex = ex; - this.ey = ey; - this.ez = ez; - this.et = et; - aCoordinate("x", ex); - aCoordinate("y", ey); - aCoordinate("z", ez); - aCoordinate("t", et); - Object.freeze(this); - } - get x() { - return this.toAffine().x; - } - get y() { - return this.toAffine().y; - } - static fromAffine(p) { - if (p instanceof Point) - throw new Error("extended point not allowed"); - const { x, y } = p || {}; - aCoordinate("x", x); - aCoordinate("y", y); - return new Point(x, y, _1n4, modP(x * y)); - } - static normalizeZ(points) { - const toInv = Fp2.invertBatch(points.map((p) => p.ez)); - return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine); - } - // Multiscalar Multiplication - static msm(points, scalars) { - return pippenger(Point, Fn, points, scalars); - } - // "Private method", don't use it directly - _setWindowSize(windowSize) { - wnaf.setWindowSize(this, windowSize); - } - // Not required for fromHex(), which always creates valid points. - // Could be useful for fromAffine(). - assertValidity() { - assertValidMemo(this); - } - // Compare one point to another. - equals(other) { - assertPoint(other); - const { ex: X1, ey: Y1, ez: Z1 } = this; - const { ex: X2, ey: Y2, ez: Z2 } = other; - const X1Z2 = modP(X1 * Z2); - const X2Z1 = modP(X2 * Z1); - const Y1Z2 = modP(Y1 * Z2); - const Y2Z1 = modP(Y2 * Z1); - return X1Z2 === X2Z1 && Y1Z2 === Y2Z1; - } - is0() { - return this.equals(Point.ZERO); - } - negate() { - return new Point(modP(-this.ex), this.ey, this.ez, modP(-this.et)); - } - // Fast algo for doubling Extended Point. - // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd - // Cost: 4M + 4S + 1*a + 6add + 1*2. - double() { - const { a } = CURVE; - const { ex: X1, ey: Y1, ez: Z1 } = this; - const A = modP(X1 * X1); - const B = modP(Y1 * Y1); - const C = modP(_2n3 * modP(Z1 * Z1)); - const D = modP(a * A); - const x1y1 = X1 + Y1; - const E = modP(modP(x1y1 * x1y1) - A - B); - const G2 = D + B; - const F = G2 - C; - const H = D - B; - const X3 = modP(E * F); - const Y3 = modP(G2 * H); - const T3 = modP(E * H); - const Z3 = modP(F * G2); - return new Point(X3, Y3, Z3, T3); - } - // Fast algo for adding 2 Extended Points. - // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-add-2008-hwcd - // Cost: 9M + 1*a + 1*d + 7add. - add(other) { - assertPoint(other); - const { a, d } = CURVE; - const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this; - const { ex: X2, ey: Y2, ez: Z2, et: T2 } = other; - if (a === BigInt(-1)) { - const A2 = modP((Y1 - X1) * (Y2 + X2)); - const B2 = modP((Y1 + X1) * (Y2 - X2)); - const F2 = modP(B2 - A2); - if (F2 === _0n4) - return this.double(); - const C2 = modP(Z1 * _2n3 * T2); - const D2 = modP(T1 * _2n3 * Z2); - const E2 = D2 + C2; - const G3 = B2 + A2; - const H2 = D2 - C2; - const X32 = modP(E2 * F2); - const Y32 = modP(G3 * H2); - const T32 = modP(E2 * H2); - const Z32 = modP(F2 * G3); - return new Point(X32, Y32, Z32, T32); - } - const A = modP(X1 * X2); - const B = modP(Y1 * Y2); - const C = modP(T1 * d * T2); - const D = modP(Z1 * Z2); - const E = modP((X1 + Y1) * (X2 + Y2) - A - B); - const F = D - C; - const G2 = D + C; - const H = modP(B - a * A); - const X3 = modP(E * F); - const Y3 = modP(G2 * H); - const T3 = modP(E * H); - const Z3 = modP(F * G2); - return new Point(X3, Y3, Z3, T3); - } - subtract(other) { - return this.add(other.negate()); - } - wNAF(n) { - return wnaf.wNAFCached(this, n, Point.normalizeZ); - } - // Constant-time multiplication. - multiply(scalar) { - const n = scalar; - aInRange("scalar", n, _1n4, CURVE_ORDER); - const { p, f } = this.wNAF(n); - return Point.normalizeZ([p, f])[0]; - } - // Non-constant-time multiplication. Uses double-and-add algorithm. - // It's faster, but should only be used when you don't care about - // an exposed private key e.g. sig verification. - // Does NOT allow scalars higher than CURVE.n. - // Accepts optional accumulator to merge with multiply (important for sparse scalars) - multiplyUnsafe(scalar, acc = Point.ZERO) { - const n = scalar; - aInRange("scalar", n, _0n4, CURVE_ORDER); - if (n === _0n4) - return I; - if (this.is0() || n === _1n4) - return this; - return wnaf.wNAFCachedUnsafe(this, n, Point.normalizeZ, acc); - } - // Checks if point is of small order. - // If you add something to small order point, you will have "dirty" - // point with torsion component. - // Multiplies point by cofactor and checks if the result is 0. - isSmallOrder() { - return this.multiplyUnsafe(cofactor).is0(); - } - // Multiplies point by curve order and checks if the result is 0. - // Returns `false` is the point is dirty. - isTorsionFree() { - return wnaf.unsafeLadder(this, CURVE_ORDER).is0(); - } - // Converts Extended point to default (x, y) coordinates. - // Can accept precomputed Z^-1 - for example, from invertBatch. - toAffine(iz) { - return toAffineMemo(this, iz); - } - clearCofactor() { - const { h: cofactor2 } = CURVE; - if (cofactor2 === _1n4) - return this; - return this.multiplyUnsafe(cofactor2); - } - // Converts hash string or Uint8Array to Point. - // Uses algo from RFC8032 5.1.3. - static fromHex(hex, zip215 = false) { - const { d, a } = CURVE; - const len = Fp2.BYTES; - hex = ensureBytes("pointHex", hex, len); - abool("zip215", zip215); - const normed = hex.slice(); - const lastByte = hex[len - 1]; - normed[len - 1] = lastByte & ~128; - const y = bytesToNumberLE(normed); - const max = zip215 ? MASK : Fp2.ORDER; - aInRange("pointHex.y", y, _0n4, max); - const y2 = modP(y * y); - const u = modP(y2 - _1n4); - const v = modP(d * y2 - a); - let { isValid, value: x } = uvRatio2(u, v); - if (!isValid) - throw new Error("Point.fromHex: invalid y coordinate"); - const isXOdd = (x & _1n4) === _1n4; - const isLastByteOdd = (lastByte & 128) !== 0; - if (!zip215 && x === _0n4 && isLastByteOdd) - throw new Error("Point.fromHex: x=0 and x_0=1"); - if (isLastByteOdd !== isXOdd) - x = modP(-x); - return Point.fromAffine({ x, y }); - } - static fromPrivateKey(privKey) { - return getExtendedPublicKey(privKey).point; - } - toRawBytes() { - const { x, y } = this.toAffine(); - const bytes = numberToBytesLE(y, Fp2.BYTES); - bytes[bytes.length - 1] |= x & _1n4 ? 128 : 0; - return bytes; - } - toHex() { - return bytesToHex(this.toRawBytes()); - } - } - Point.BASE = new Point(CURVE.Gx, CURVE.Gy, _1n4, modP(CURVE.Gx * CURVE.Gy)); - Point.ZERO = new Point(_0n4, _1n4, _1n4, _0n4); - const { BASE: G, ZERO: I } = Point; - const wnaf = wNAF(Point, nByteLength * 8); - function modN(a) { - return mod(a, CURVE_ORDER); - } - __name(modN, "modN"); - function modN_LE(hash) { - return modN(bytesToNumberLE(hash)); - } - __name(modN_LE, "modN_LE"); - function getExtendedPublicKey(key) { - const len = Fp2.BYTES; - key = ensureBytes("private key", key, len); - const hashed = ensureBytes("hashed private key", cHash(key), 2 * len); - const head = adjustScalarBytes2(hashed.slice(0, len)); - const prefix = hashed.slice(len, 2 * len); - const scalar = modN_LE(head); - const point = G.multiply(scalar); - const pointBytes = point.toRawBytes(); - return { head, prefix, scalar, point, pointBytes }; - } - __name(getExtendedPublicKey, "getExtendedPublicKey"); - function getPublicKey(privKey) { - return getExtendedPublicKey(privKey).pointBytes; - } - __name(getPublicKey, "getPublicKey"); - function hashDomainToScalar(context = new Uint8Array(), ...msgs) { - const msg = concatBytes(...msgs); - return modN_LE(cHash(domain(msg, ensureBytes("context", context), !!prehash))); - } - __name(hashDomainToScalar, "hashDomainToScalar"); - function sign(msg, privKey, options = {}) { - msg = ensureBytes("message", msg); - if (prehash) - msg = prehash(msg); - const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey); - const r = hashDomainToScalar(options.context, prefix, msg); - const R = G.multiply(r).toRawBytes(); - const k = hashDomainToScalar(options.context, R, pointBytes, msg); - const s = modN(r + k * scalar); - aInRange("signature.s", s, _0n4, CURVE_ORDER); - const res = concatBytes(R, numberToBytesLE(s, Fp2.BYTES)); - return ensureBytes("result", res, Fp2.BYTES * 2); - } - __name(sign, "sign"); - const verifyOpts = VERIFY_DEFAULT; - function verify(sig, msg, publicKey2, options = verifyOpts) { - const { context, zip215 } = options; - const len = Fp2.BYTES; - sig = ensureBytes("signature", sig, 2 * len); - msg = ensureBytes("message", msg); - publicKey2 = ensureBytes("publicKey", publicKey2, len); - if (zip215 !== void 0) - abool("zip215", zip215); - if (prehash) - msg = prehash(msg); - const s = bytesToNumberLE(sig.slice(len, 2 * len)); - let A, R, SB; - try { - A = Point.fromHex(publicKey2, zip215); - R = Point.fromHex(sig.slice(0, len), zip215); - SB = G.multiplyUnsafe(s); - } catch (error) { - return false; - } - if (!zip215 && A.isSmallOrder()) - return false; - const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg); - const RkA = R.add(A.multiplyUnsafe(k)); - return RkA.subtract(SB).clearCofactor().equals(Point.ZERO); - } - __name(verify, "verify"); - G._setWindowSize(8); - const utils2 = { - getExtendedPublicKey, - // ed25519 private keys are uniform 32b. No need to check for modulo bias, like in secp256k1. - randomPrivateKey: /* @__PURE__ */ __name(() => randomBytes2(Fp2.BYTES), "randomPrivateKey"), - /** - * We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT - * values. This slows down first getPublicKey() by milliseconds (see Speed section), - * but allows to speed-up subsequent getPublicKey() calls up to 20x. - * @param windowSize 2, 4, 8, 16 - */ - precompute(windowSize = 8, point = Point.BASE) { - point._setWindowSize(windowSize); - point.multiply(BigInt(3)); - return point; - } - }; - return { - CURVE, - getPublicKey, - sign, - verify, - ExtendedPoint: Point, - utils: utils2 - }; - } - __name(twistedEdwards, "twistedEdwards"); - - // ../../node_modules/@noble/curves/esm/ed25519.js - var ED25519_P = BigInt("57896044618658097711785492504343953926634992332820282019728792003956564819949"); - var ED25519_SQRT_M1 = /* @__PURE__ */ BigInt("19681161376707505956807079304988542015446066515923890162744021073123829784752"); - var _0n5 = BigInt(0); - var _1n5 = BigInt(1); - var _2n4 = BigInt(2); - var _3n2 = BigInt(3); - var _5n2 = BigInt(5); - var _8n3 = BigInt(8); - function ed25519_pow_2_252_3(x) { - const _10n = BigInt(10), _20n = BigInt(20), _40n = BigInt(40), _80n = BigInt(80); - const P2 = ED25519_P; - const x2 = x * x % P2; - const b2 = x2 * x % P2; - const b4 = pow2(b2, _2n4, P2) * b2 % P2; - const b5 = pow2(b4, _1n5, P2) * x % P2; - const b10 = pow2(b5, _5n2, P2) * b5 % P2; - const b20 = pow2(b10, _10n, P2) * b10 % P2; - const b40 = pow2(b20, _20n, P2) * b20 % P2; - const b80 = pow2(b40, _40n, P2) * b40 % P2; - const b160 = pow2(b80, _80n, P2) * b80 % P2; - const b240 = pow2(b160, _80n, P2) * b80 % P2; - const b250 = pow2(b240, _10n, P2) * b10 % P2; - const pow_p_5_8 = pow2(b250, _2n4, P2) * x % P2; - return { pow_p_5_8, b2 }; - } - __name(ed25519_pow_2_252_3, "ed25519_pow_2_252_3"); - function adjustScalarBytes(bytes) { - bytes[0] &= 248; - bytes[31] &= 127; - bytes[31] |= 64; - return bytes; - } - __name(adjustScalarBytes, "adjustScalarBytes"); - function uvRatio(u, v) { - const P2 = ED25519_P; - const v3 = mod(v * v * v, P2); - const v7 = mod(v3 * v3 * v, P2); - const pow3 = ed25519_pow_2_252_3(u * v7).pow_p_5_8; - let x = mod(u * v3 * pow3, P2); - const vx2 = mod(v * x * x, P2); - const root1 = x; - const root2 = mod(x * ED25519_SQRT_M1, P2); - const useRoot1 = vx2 === u; - const useRoot2 = vx2 === mod(-u, P2); - const noRoot = vx2 === mod(-u * ED25519_SQRT_M1, P2); - if (useRoot1) - x = root1; - if (useRoot2 || noRoot) - x = root2; - if (isNegativeLE(x, P2)) - x = mod(-x, P2); - return { isValid: useRoot1 || useRoot2, value: x }; - } - __name(uvRatio, "uvRatio"); - var Fp = /* @__PURE__ */ (() => Field(ED25519_P, void 0, true))(); - var ed25519Defaults = /* @__PURE__ */ (() => ({ - // Param: a - a: BigInt(-1), - // Fp.create(-1) is proper; our way still works and is faster - // d is equal to -121665/121666 over finite field. - // Negative number is P - number, and division is invert(number, P) - d: BigInt("37095705934669439343138083508754565189542113879843219016388785533085940283555"), - // Finite field 𝔽p over which we'll do calculations; 2n**255n - 19n - Fp, - // Subgroup order: how many points curve has - // 2n**252n + 27742317777372353535851937790883648493n; - n: BigInt("7237005577332262213973186563042994240857116359379907606001950938285454250989"), - // Cofactor - h: _8n3, - // Base point (x, y) aka generator point - Gx: BigInt("15112221349535400772501151409588531511454012693041857206046113283949847762202"), - Gy: BigInt("46316835694926478169428394003475163141307993866256225615783033603165251855960"), - hash: sha512, - randomBytes, - adjustScalarBytes, - // dom2 - // Ratio of u to v. Allows us to combine inversion and square root. Uses algo from RFC8032 5.1.3. - // Constant-time, u/√v - uvRatio - }))(); - var ed25519 = /* @__PURE__ */ (() => twistedEdwards(ed25519Defaults))(); - - // ../../node_modules/@noble/hashes/esm/sha256.js - var SHA256_K = /* @__PURE__ */ new Uint32Array([ - 1116352408, - 1899447441, - 3049323471, - 3921009573, - 961987163, - 1508970993, - 2453635748, - 2870763221, - 3624381080, - 310598401, - 607225278, - 1426881987, - 1925078388, - 2162078206, - 2614888103, - 3248222580, - 3835390401, - 4022224774, - 264347078, - 604807628, - 770255983, - 1249150122, - 1555081692, - 1996064986, - 2554220882, - 2821834349, - 2952996808, - 3210313671, - 3336571891, - 3584528711, - 113926993, - 338241895, - 666307205, - 773529912, - 1294757372, - 1396182291, - 1695183700, - 1986661051, - 2177026350, - 2456956037, - 2730485921, - 2820302411, - 3259730800, - 3345764771, - 3516065817, - 3600352804, - 4094571909, - 275423344, - 430227734, - 506948616, - 659060556, - 883997877, - 958139571, - 1322822218, - 1537002063, - 1747873779, - 1955562222, - 2024104815, - 2227730452, - 2361852424, - 2428436474, - 2756734187, - 3204031479, - 3329325298 - ]); - var SHA256_IV = /* @__PURE__ */ new Uint32Array([ - 1779033703, - 3144134277, - 1013904242, - 2773480762, - 1359893119, - 2600822924, - 528734635, - 1541459225 - ]); - var SHA256_W = /* @__PURE__ */ new Uint32Array(64); - var SHA256 = class extends HashMD { - static { - __name(this, "SHA256"); - } - constructor() { - super(64, 32, 8, false); - this.A = SHA256_IV[0] | 0; - this.B = SHA256_IV[1] | 0; - this.C = SHA256_IV[2] | 0; - this.D = SHA256_IV[3] | 0; - this.E = SHA256_IV[4] | 0; - this.F = SHA256_IV[5] | 0; - this.G = SHA256_IV[6] | 0; - this.H = SHA256_IV[7] | 0; - } - get() { - const { A, B, C, D, E, F, G, H } = this; - return [A, B, C, D, E, F, G, H]; - } - // prettier-ignore - set(A, B, C, D, E, F, G, H) { - this.A = A | 0; - this.B = B | 0; - this.C = C | 0; - this.D = D | 0; - this.E = E | 0; - this.F = F | 0; - this.G = G | 0; - this.H = H | 0; - } - process(view2, offset) { - for (let i = 0; i < 16; i++, offset += 4) - SHA256_W[i] = view2.getUint32(offset, false); - for (let i = 16; i < 64; i++) { - const W15 = SHA256_W[i - 15]; - const W2 = SHA256_W[i - 2]; - const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3; - const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10; - SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0; - } - let { A, B, C, D, E, F, G, H } = this; - for (let i = 0; i < 64; i++) { - const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25); - const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0; - const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22); - const T2 = sigma0 + Maj(A, B, C) | 0; - H = G; - G = F; - F = E; - E = D + T1 | 0; - D = C; - C = B; - B = A; - A = T1 + T2 | 0; - } - A = A + this.A | 0; - B = B + this.B | 0; - C = C + this.C | 0; - D = D + this.D | 0; - E = E + this.E | 0; - F = F + this.F | 0; - G = G + this.G | 0; - H = H + this.H | 0; - this.set(A, B, C, D, E, F, G, H); - } - roundClean() { - SHA256_W.fill(0); - } - destroy() { - this.set(0, 0, 0, 0, 0, 0, 0, 0); - this.buffer.fill(0); - } - }; - var sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256()); - - // ../utils/node_modules/base58-js/base58_chars.js - var base58_chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - var base58_chars_default = base58_chars; - - // ../utils/node_modules/base58-js/base58_to_binary.js - function base58_to_binary(base58String) { - if (!base58String || typeof base58String !== "string") - throw new Error(`Expected base58 string but got \u201C${base58String}\u201D`); - if (base58String.match(/[IOl0]/gmu)) - throw new Error( - `Invalid base58 character \u201C${base58String.match(/[IOl0]/gmu)}\u201D` - ); - const lz = base58String.match(/^1+/gmu); - const psz = lz ? lz[0].length : 0; - const size = (base58String.length - psz) * (Math.log(58) / Math.log(256)) + 1 >>> 0; - return new Uint8Array([ - ...new Uint8Array(psz), - ...base58String.match(/.{1}/gmu).map((i) => base58_chars_default.indexOf(i)).reduce((acc, i) => { - acc = acc.map((j) => { - const x = j * 58 + i; - i = x >> 8; - return x; - }); - return acc; - }, new Uint8Array(size)).reverse().filter( - /* @__PURE__ */ ((lastValue) => (value) => ( - // @ts-ignore - lastValue = lastValue || value - ))(false) - ) - ]); - } - __name(base58_to_binary, "base58_to_binary"); - var base58_to_binary_default = base58_to_binary; - - // ../utils/node_modules/base58-js/create_base58_map.js - var create_base58_map = /* @__PURE__ */ __name(() => { - const base58M = Array(256).fill(-1); - for (let i = 0; i < base58_chars_default.length; ++i) - base58M[base58_chars_default.charCodeAt(i)] = i; - return base58M; - }, "create_base58_map"); - var create_base58_map_default = create_base58_map; - - // ../utils/node_modules/base58-js/binary_to_base58.js - var base58Map = create_base58_map_default(); - function binary_to_base58(uint8array) { - const result = []; - for (const byte of uint8array) { - let carry = byte; - for (let j = 0; j < result.length; ++j) { - const x = (base58Map[result[j]] << 8) + carry; - result[j] = base58_chars_default.charCodeAt(x % 58); - carry = x / 58 | 0; - } - while (carry) { - result.push(base58_chars_default.charCodeAt(carry % 58)); - carry = carry / 58 | 0; - } - } - for (const byte of uint8array) - if (byte) break; - else result.push("1".charCodeAt(0)); - result.reverse(); - return String.fromCharCode(...result); - } - __name(binary_to_base58, "binary_to_base58"); - var binary_to_base58_default = binary_to_base58; - - // ../../node_modules/js-base64/base64.mjs - var _hasBuffer = typeof Buffer === "function"; - var _TD = typeof TextDecoder === "function" ? new TextDecoder() : void 0; - var _TE = typeof TextEncoder === "function" ? new TextEncoder() : void 0; - var b64ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - var b64chs = Array.prototype.slice.call(b64ch); - var b64tab = ((a) => { - let tab = {}; - a.forEach((c, i) => tab[c] = i); - return tab; - })(b64chs); - var b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/; - var _fromCC = String.fromCharCode.bind(String); - var _U8Afrom = typeof Uint8Array.from === "function" ? Uint8Array.from.bind(Uint8Array) : (it) => new Uint8Array(Array.prototype.slice.call(it, 0)); - var _mkUriSafe = /* @__PURE__ */ __name((src) => src.replace(/=/g, "").replace(/[+\/]/g, (m0) => m0 == "+" ? "-" : "_"), "_mkUriSafe"); - var _tidyB64 = /* @__PURE__ */ __name((s) => s.replace(/[^A-Za-z0-9\+\/]/g, ""), "_tidyB64"); - var btoaPolyfill = /* @__PURE__ */ __name((bin) => { - let u32, c0, c1, c2, asc = ""; - const pad = bin.length % 3; - for (let i = 0; i < bin.length; ) { - if ((c0 = bin.charCodeAt(i++)) > 255 || (c1 = bin.charCodeAt(i++)) > 255 || (c2 = bin.charCodeAt(i++)) > 255) - throw new TypeError("invalid character found"); - u32 = c0 << 16 | c1 << 8 | c2; - asc += b64chs[u32 >> 18 & 63] + b64chs[u32 >> 12 & 63] + b64chs[u32 >> 6 & 63] + b64chs[u32 & 63]; - } - return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc; - }, "btoaPolyfill"); - var _btoa = typeof btoa === "function" ? (bin) => btoa(bin) : _hasBuffer ? (bin) => Buffer.from(bin, "binary").toString("base64") : btoaPolyfill; - var _fromUint8Array = _hasBuffer ? (u8a) => Buffer.from(u8a).toString("base64") : (u8a) => { - const maxargs = 4096; - let strs = []; - for (let i = 0, l = u8a.length; i < l; i += maxargs) { - strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs))); - } - return _btoa(strs.join("")); - }; - var fromUint8Array = /* @__PURE__ */ __name((u8a, urlsafe = false) => urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a), "fromUint8Array"); - var cb_utob = /* @__PURE__ */ __name((c) => { - if (c.length < 2) { - var cc = c.charCodeAt(0); - return cc < 128 ? c : cc < 2048 ? _fromCC(192 | cc >>> 6) + _fromCC(128 | cc & 63) : _fromCC(224 | cc >>> 12 & 15) + _fromCC(128 | cc >>> 6 & 63) + _fromCC(128 | cc & 63); - } else { - var cc = 65536 + (c.charCodeAt(0) - 55296) * 1024 + (c.charCodeAt(1) - 56320); - return _fromCC(240 | cc >>> 18 & 7) + _fromCC(128 | cc >>> 12 & 63) + _fromCC(128 | cc >>> 6 & 63) + _fromCC(128 | cc & 63); - } - }, "cb_utob"); - var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; - var utob = /* @__PURE__ */ __name((u) => u.replace(re_utob, cb_utob), "utob"); - var _encode = _hasBuffer ? (s) => Buffer.from(s, "utf8").toString("base64") : _TE ? (s) => _fromUint8Array(_TE.encode(s)) : (s) => _btoa(utob(s)); - var encode = /* @__PURE__ */ __name((src, urlsafe = false) => urlsafe ? _mkUriSafe(_encode(src)) : _encode(src), "encode"); - var re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g; - var cb_btou = /* @__PURE__ */ __name((cccc) => { - switch (cccc.length) { - case 4: - var cp = (7 & cccc.charCodeAt(0)) << 18 | (63 & cccc.charCodeAt(1)) << 12 | (63 & cccc.charCodeAt(2)) << 6 | 63 & cccc.charCodeAt(3), offset = cp - 65536; - return _fromCC((offset >>> 10) + 55296) + _fromCC((offset & 1023) + 56320); - case 3: - return _fromCC((15 & cccc.charCodeAt(0)) << 12 | (63 & cccc.charCodeAt(1)) << 6 | 63 & cccc.charCodeAt(2)); - default: - return _fromCC((31 & cccc.charCodeAt(0)) << 6 | 63 & cccc.charCodeAt(1)); - } - }, "cb_btou"); - var btou = /* @__PURE__ */ __name((b) => b.replace(re_btou, cb_btou), "btou"); - var atobPolyfill = /* @__PURE__ */ __name((asc) => { - asc = asc.replace(/\s+/g, ""); - if (!b64re.test(asc)) - throw new TypeError("malformed base64."); - asc += "==".slice(2 - (asc.length & 3)); - let u24, bin = "", r1, r2; - for (let i = 0; i < asc.length; ) { - u24 = b64tab[asc.charAt(i++)] << 18 | b64tab[asc.charAt(i++)] << 12 | (r1 = b64tab[asc.charAt(i++)]) << 6 | (r2 = b64tab[asc.charAt(i++)]); - bin += r1 === 64 ? _fromCC(u24 >> 16 & 255) : r2 === 64 ? _fromCC(u24 >> 16 & 255, u24 >> 8 & 255) : _fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255); - } - return bin; - }, "atobPolyfill"); - var _atob = typeof atob === "function" ? (asc) => atob(_tidyB64(asc)) : _hasBuffer ? (asc) => Buffer.from(asc, "base64").toString("binary") : atobPolyfill; - var _toUint8Array = _hasBuffer ? (a) => _U8Afrom(Buffer.from(a, "base64")) : (a) => _U8Afrom(_atob(a).split("").map((c) => c.charCodeAt(0))); - var toUint8Array = /* @__PURE__ */ __name((a) => _toUint8Array(_unURI(a)), "toUint8Array"); - var _decode = _hasBuffer ? (a) => Buffer.from(a, "base64").toString("utf8") : _TD ? (a) => _TD.decode(_toUint8Array(a)) : (a) => btou(_atob(a)); - var _unURI = /* @__PURE__ */ __name((a) => _tidyB64(a.replace(/[-_]/g, (m0) => m0 == "-" ? "+" : "/")), "_unURI"); - var decode = /* @__PURE__ */ __name((src) => _decode(_unURI(src)), "decode"); - - // ../utils/src/storage.ts - var LsPrefix = "__fastnear_"; - var createDefaultStorage = /* @__PURE__ */ __name(() => typeof localStorage !== "undefined" ? localStorage : { - getItem: /* @__PURE__ */ __name((key) => memoryStore.get(key) || null, "getItem"), - setItem: /* @__PURE__ */ __name((key, value) => memoryStore.set(key, value), "setItem"), - removeItem: /* @__PURE__ */ __name((key) => memoryStore.delete(key), "removeItem"), - clear: /* @__PURE__ */ __name(() => memoryStore.clear(), "clear") - }, "createDefaultStorage"); - var memoryStore = /* @__PURE__ */ new Map(); - var storageBackend = createDefaultStorage(); - var storage = { - setBackend: /* @__PURE__ */ __name((customBackend) => { - storageBackend = customBackend; - }, "setBackend"), - set: /* @__PURE__ */ __name((key, value) => { - if (value === null || value === void 0) { - storageBackend.removeItem(LsPrefix + key); - } else { - storageBackend.setItem(LsPrefix + key, JSON.stringify(value)); - } - }, "set"), - get: /* @__PURE__ */ __name((key) => { - const value = storageBackend.getItem(LsPrefix + key); - if (value === null) return null; - try { - return JSON.parse(value); - } catch { - return value; - } - }, "get"), - remove: /* @__PURE__ */ __name((key) => storageBackend.removeItem(key), "remove"), - clear: /* @__PURE__ */ __name(() => storageBackend.clear(), "clear") - }; - - // ../utils/src/misc.ts - function toHex(data) { - return Array.from(data).map((b) => b.toString(16).padStart(2, "0")).join(""); - } - __name(toHex, "toHex"); - function fromHex(hex) { - if (hex.length % 2) throw new Error("Hex string must be even length"); - const bytes = new Uint8Array(hex.length / 2); - for (let i = 0; i < hex.length; i += 2) { - bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16); - } - return bytes; - } - __name(fromHex, "fromHex"); - function base64ToBytes(b64Val) { - return toUint8Array(b64Val); - } - __name(base64ToBytes, "base64ToBytes"); - function bytesToBase64(bytesArr) { - return fromUint8Array(bytesArr); - } - __name(bytesToBase64, "bytesToBase64"); - function toBase64(strVal) { - try { - return encode(strVal); - } catch (e) { - console.error("Issue base64 encoding", e); - return null; - } - } - __name(toBase64, "toBase64"); - function fromBase64(strVal) { - try { - return decode(strVal); - } catch (e) { - console.error("Issue base64 decoding", e); - return null; - } - } - __name(fromBase64, "fromBase64"); - function convertUnit(s, ...args) { - if (Array.isArray(s)) { - s = s.reduce((acc, part, i) => { - return acc + (args[i - 1] ?? "") + part; - }); - } - if (typeof s == "string") { - const match = s.match(/([0-9.,_]+)\s*([a-zA-Z]+)?/); - if (match) { - const amount = match[1].replace(/[_,]/g, ""); - const unitPart = match[2]; - if (unitPart) { - switch (unitPart.toLowerCase()) { - case "near": - return big_default(amount).mul(big_default(10).pow(24)).toFixed(0); - case "tgas": - return big_default(amount).mul(big_default(10).pow(12)).toFixed(0); - case "ggas": - return big_default(amount).mul(big_default(10).pow(9)).toFixed(0); - case "gas": - case "yoctonear": - return big_default(amount).toFixed(0); - default: - throw new Error(`Unknown unit: ${unitPart}`); - } - } else { - return big_default(amount).toFixed(0); - } - } - } - return big_default(`${s}`).toFixed(0); - } - __name(convertUnit, "convertUnit"); - function lsSet(key, value) { - storage.set(key, value); - } - __name(lsSet, "lsSet"); - function lsGet(key) { - return storage.get(key); - } - __name(lsGet, "lsGet"); - function deepCopy(obj) { - return JSON.parse(JSON.stringify(obj)); - } - __name(deepCopy, "deepCopy"); - function tryParseJson(...args) { - try { - return JSON.parse(args[0]); - } catch { - if (args.length > 1) { - return args[1]; - } - return args[0]; - } - } - __name(tryParseJson, "tryParseJson"); - function parseJsonFromBytes(bytes) { - try { - const decoder = new TextDecoder(); - return JSON.parse( - decoder.decode(bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes)) - ); - } catch (e) { - try { - return bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes); - } catch (e2) { - return bytes; - } - } - } - __name(parseJsonFromBytes, "parseJsonFromBytes"); - function canSignWithLAK(actions2) { - return actions2.length === 1 && actions2[0].type === "FunctionCall" && big_default(actions2[0]?.deposit ?? "0").eq(0); - } - __name(canSignWithLAK, "canSignWithLAK"); - - // ../utils/src/crypto.ts - var keyFromString = /* @__PURE__ */ __name((key) => base58_to_binary_default( - key.includes(":") ? (() => { - const [curve, keyPart] = key.split(":"); - if (curve !== "ed25519") { - throw new Error(`Unsupported curve: ${curve}`); - } - return keyPart; - })() : key - ), "keyFromString"); - var keyToString = /* @__PURE__ */ __name((key) => `ed25519:${binary_to_base58_default(key)}`, "keyToString"); - function publicKeyFromPrivate(privateKey) { - const secret = keyFromString(privateKey).slice(0, 32); - const publicKey2 = ed25519.getPublicKey(secret); - return keyToString(publicKey2); - } - __name(publicKeyFromPrivate, "publicKeyFromPrivate"); - function privateKeyFromRandom() { - const privateKey = crypto.getRandomValues(new Uint8Array(64)); - return keyToString(privateKey); - } - __name(privateKeyFromRandom, "privateKeyFromRandom"); - function signHash(hashBytes, privateKey, opts) { - const secret = keyFromString(privateKey).slice(0, 32); - const signature = ed25519.sign(hashBytes, secret); - if (opts?.returnBase58) { - return binary_to_base58_default(signature); - } - return signature; - } - __name(signHash, "signHash"); - function signBytes(bytes, privateKey) { - const hash = sha256(bytes); - return signHash(hash, privateKey); - } - __name(signBytes, "signBytes"); - - // ../../node_modules/borsh/lib/esm/types.js - var integers = ["u8", "u16", "u32", "u64", "u128", "i8", "i16", "i32", "i64", "i128", "f32", "f64"]; - - // ../../node_modules/borsh/lib/esm/buffer.js - var EncodeBuffer = ( - /** @class */ - function() { - function EncodeBuffer2() { - this.offset = 0; - this.buffer_size = 256; - this.buffer = new ArrayBuffer(this.buffer_size); - this.view = new DataView(this.buffer); - } - __name(EncodeBuffer2, "EncodeBuffer"); - EncodeBuffer2.prototype.resize_if_necessary = function(needed_space) { - if (this.buffer_size - this.offset < needed_space) { - this.buffer_size = Math.max(this.buffer_size * 2, this.buffer_size + needed_space); - var new_buffer = new ArrayBuffer(this.buffer_size); - new Uint8Array(new_buffer).set(new Uint8Array(this.buffer)); - this.buffer = new_buffer; - this.view = new DataView(new_buffer); - } - }; - EncodeBuffer2.prototype.get_used_buffer = function() { - return new Uint8Array(this.buffer).slice(0, this.offset); - }; - EncodeBuffer2.prototype.store_value = function(value, type) { - var bSize = type.substring(1); - var size = parseInt(bSize) / 8; - this.resize_if_necessary(size); - var toCall = type[0] === "f" ? "setFloat".concat(bSize) : type[0] === "i" ? "setInt".concat(bSize) : "setUint".concat(bSize); - this.view[toCall](this.offset, value, true); - this.offset += size; - }; - EncodeBuffer2.prototype.store_bytes = function(from) { - this.resize_if_necessary(from.length); - new Uint8Array(this.buffer).set(new Uint8Array(from), this.offset); - this.offset += from.length; - }; - return EncodeBuffer2; - }() - ); - var DecodeBuffer = ( - /** @class */ - function() { - function DecodeBuffer2(buf) { - this.offset = 0; - this.buffer_size = buf.length; - this.buffer = new ArrayBuffer(buf.length); - new Uint8Array(this.buffer).set(buf); - this.view = new DataView(this.buffer); - } - __name(DecodeBuffer2, "DecodeBuffer"); - DecodeBuffer2.prototype.assert_enough_buffer = function(size) { - if (this.offset + size > this.buffer.byteLength) { - throw new Error("Error in schema, the buffer is smaller than expected"); - } - }; - DecodeBuffer2.prototype.consume_value = function(type) { - var bSize = type.substring(1); - var size = parseInt(bSize) / 8; - this.assert_enough_buffer(size); - var toCall = type[0] === "f" ? "getFloat".concat(bSize) : type[0] === "i" ? "getInt".concat(bSize) : "getUint".concat(bSize); - var ret = this.view[toCall](this.offset, true); - this.offset += size; - return ret; - }; - DecodeBuffer2.prototype.consume_bytes = function(size) { - this.assert_enough_buffer(size); - var ret = this.buffer.slice(this.offset, this.offset + size); - this.offset += size; - return ret; - }; - return DecodeBuffer2; - }() - ); - - // ../../node_modules/borsh/lib/esm/utils.js - var __extends = /* @__PURE__ */ function() { - var extendStatics = /* @__PURE__ */ __name(function(d, b) { - extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) { - d2.__proto__ = b2; - } || function(d2, b2) { - for (var p in b2) if (Object.prototype.hasOwnProperty.call(b2, p)) d2[p] = b2[p]; - }; - return extendStatics(d, b); - }, "extendStatics"); - return function(d, b) { - if (typeof b !== "function" && b !== null) - throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); - extendStatics(d, b); - function __() { - this.constructor = d; - } - __name(__, "__"); - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; - }(); - function isArrayLike(value) { - return Array.isArray(value) || !!value && typeof value === "object" && "length" in value && typeof value.length === "number" && (value.length === 0 || value.length > 0 && value.length - 1 in value); - } - __name(isArrayLike, "isArrayLike"); - function expect_type(value, type, fieldPath) { - if (typeof value !== type) { - throw new Error("Expected ".concat(type, " not ").concat(typeof value, "(").concat(value, ") at ").concat(fieldPath.join("."))); - } - } - __name(expect_type, "expect_type"); - function expect_bigint(value, fieldPath) { - var basicType = ["number", "string", "bigint", "boolean"].includes(typeof value); - var strObject = typeof value === "object" && value !== null && "toString" in value; - if (!basicType && !strObject) { - throw new Error("Expected bigint, number, boolean or string not ".concat(typeof value, "(").concat(value, ") at ").concat(fieldPath.join("."))); - } - } - __name(expect_bigint, "expect_bigint"); - function expect_same_size(length, expected, fieldPath) { - if (length !== expected) { - throw new Error("Array length ".concat(length, " does not match schema length ").concat(expected, " at ").concat(fieldPath.join("."))); - } - } - __name(expect_same_size, "expect_same_size"); - function expect_enum(value, fieldPath) { - if (typeof value !== "object" || value === null) { - throw new Error("Expected object not ".concat(typeof value, "(").concat(value, ") at ").concat(fieldPath.join("."))); - } - } - __name(expect_enum, "expect_enum"); - var VALID_STRING_TYPES = integers.concat(["bool", "string"]); - var VALID_OBJECT_KEYS = ["option", "enum", "array", "set", "map", "struct"]; - var ErrorSchema = ( - /** @class */ - function(_super) { - __extends(ErrorSchema2, _super); - function ErrorSchema2(schema, expected) { - var message = "Invalid schema: ".concat(JSON.stringify(schema), " expected ").concat(expected); - return _super.call(this, message) || this; - } - __name(ErrorSchema2, "ErrorSchema"); - return ErrorSchema2; - }(Error) - ); - function validate_schema(schema) { - if (typeof schema === "string" && VALID_STRING_TYPES.includes(schema)) { - return; - } - if (schema && typeof schema === "object") { - var keys = Object.keys(schema); - if (keys.length === 1 && VALID_OBJECT_KEYS.includes(keys[0])) { - var key = keys[0]; - if (key === "option") - return validate_schema(schema[key]); - if (key === "enum") - return validate_enum_schema(schema[key]); - if (key === "array") - return validate_array_schema(schema[key]); - if (key === "set") - return validate_schema(schema[key]); - if (key === "map") - return validate_map_schema(schema[key]); - if (key === "struct") - return validate_struct_schema(schema[key]); - } - } - throw new ErrorSchema(schema, VALID_OBJECT_KEYS.join(", ") + " or " + VALID_STRING_TYPES.join(", ")); - } - __name(validate_schema, "validate_schema"); - function validate_enum_schema(schema) { - if (!Array.isArray(schema)) - throw new ErrorSchema(schema, "Array"); - for (var _i = 0, schema_1 = schema; _i < schema_1.length; _i++) { - var sch = schema_1[_i]; - if (typeof sch !== "object" || !("struct" in sch)) { - throw new Error('Missing "struct" key in enum schema'); - } - if (typeof sch.struct !== "object" || Object.keys(sch.struct).length !== 1) { - throw new Error('The "struct" in each enum must have a single key'); - } - validate_schema({ struct: sch.struct }); - } - } - __name(validate_enum_schema, "validate_enum_schema"); - function validate_array_schema(schema) { - if (typeof schema !== "object") - throw new ErrorSchema(schema, "{ type, len? }"); - if (schema.len && typeof schema.len !== "number") { - throw new Error("Invalid schema: ".concat(schema)); - } - if ("type" in schema) - return validate_schema(schema.type); - throw new ErrorSchema(schema, "{ type, len? }"); - } - __name(validate_array_schema, "validate_array_schema"); - function validate_map_schema(schema) { - if (typeof schema === "object" && "key" in schema && "value" in schema) { - validate_schema(schema.key); - validate_schema(schema.value); - } else { - throw new ErrorSchema(schema, "{ key, value }"); - } - } - __name(validate_map_schema, "validate_map_schema"); - function validate_struct_schema(schema) { - if (typeof schema !== "object") - throw new ErrorSchema(schema, "object"); - for (var key in schema) { - validate_schema(schema[key]); - } - } - __name(validate_struct_schema, "validate_struct_schema"); - - // ../../node_modules/borsh/lib/esm/serialize.js - var BorshSerializer = ( - /** @class */ - function() { - function BorshSerializer2(checkTypes) { - this.encoded = new EncodeBuffer(); - this.fieldPath = ["value"]; - this.checkTypes = checkTypes; - } - __name(BorshSerializer2, "BorshSerializer"); - BorshSerializer2.prototype.encode = function(value, schema) { - this.encode_value(value, schema); - return this.encoded.get_used_buffer(); - }; - BorshSerializer2.prototype.encode_value = function(value, schema) { - if (typeof schema === "string") { - if (integers.includes(schema)) - return this.encode_integer(value, schema); - if (schema === "string") - return this.encode_string(value); - if (schema === "bool") - return this.encode_boolean(value); - } - if (typeof schema === "object") { - if ("option" in schema) - return this.encode_option(value, schema); - if ("enum" in schema) - return this.encode_enum(value, schema); - if ("array" in schema) - return this.encode_array(value, schema); - if ("set" in schema) - return this.encode_set(value, schema); - if ("map" in schema) - return this.encode_map(value, schema); - if ("struct" in schema) - return this.encode_struct(value, schema); - } - }; - BorshSerializer2.prototype.encode_integer = function(value, schema) { - var size = parseInt(schema.substring(1)); - if (size <= 32 || schema == "f64") { - this.checkTypes && expect_type(value, "number", this.fieldPath); - this.encoded.store_value(value, schema); - } else { - this.checkTypes && expect_bigint(value, this.fieldPath); - this.encode_bigint(BigInt(value), size); - } - }; - BorshSerializer2.prototype.encode_bigint = function(value, size) { - var buffer_len = size / 8; - var buffer = new Uint8Array(buffer_len); - for (var i = 0; i < buffer_len; i++) { - buffer[i] = Number(value & BigInt(255)); - value = value >> BigInt(8); - } - this.encoded.store_bytes(new Uint8Array(buffer)); - }; - BorshSerializer2.prototype.encode_string = function(value) { - this.checkTypes && expect_type(value, "string", this.fieldPath); - var _value = value; - var utf8Bytes = []; - for (var i = 0; i < _value.length; i++) { - var charCode = _value.charCodeAt(i); - if (charCode < 128) { - utf8Bytes.push(charCode); - } else if (charCode < 2048) { - utf8Bytes.push(192 | charCode >> 6, 128 | charCode & 63); - } else if (charCode < 55296 || charCode >= 57344) { - utf8Bytes.push(224 | charCode >> 12, 128 | charCode >> 6 & 63, 128 | charCode & 63); - } else { - i++; - charCode = 65536 + ((charCode & 1023) << 10 | _value.charCodeAt(i) & 1023); - utf8Bytes.push(240 | charCode >> 18, 128 | charCode >> 12 & 63, 128 | charCode >> 6 & 63, 128 | charCode & 63); - } - } - this.encoded.store_value(utf8Bytes.length, "u32"); - this.encoded.store_bytes(new Uint8Array(utf8Bytes)); - }; - BorshSerializer2.prototype.encode_boolean = function(value) { - this.checkTypes && expect_type(value, "boolean", this.fieldPath); - this.encoded.store_value(value ? 1 : 0, "u8"); - }; - BorshSerializer2.prototype.encode_option = function(value, schema) { - if (value === null || value === void 0) { - this.encoded.store_value(0, "u8"); - } else { - this.encoded.store_value(1, "u8"); - this.encode_value(value, schema.option); - } - }; - BorshSerializer2.prototype.encode_enum = function(value, schema) { - this.checkTypes && expect_enum(value, this.fieldPath); - var valueKey = Object.keys(value)[0]; - for (var i = 0; i < schema["enum"].length; i++) { - var valueSchema = schema["enum"][i]; - if (valueKey === Object.keys(valueSchema.struct)[0]) { - this.encoded.store_value(i, "u8"); - return this.encode_struct(value, valueSchema); - } - } - throw new Error("Enum key (".concat(valueKey, ") not found in enum schema: ").concat(JSON.stringify(schema), " at ").concat(this.fieldPath.join("."))); - }; - BorshSerializer2.prototype.encode_array = function(value, schema) { - if (isArrayLike(value)) - return this.encode_arraylike(value, schema); - if (value instanceof ArrayBuffer) - return this.encode_buffer(value, schema); - throw new Error("Expected Array-like not ".concat(typeof value, "(").concat(value, ") at ").concat(this.fieldPath.join("."))); - }; - BorshSerializer2.prototype.encode_arraylike = function(value, schema) { - if (schema.array.len) { - expect_same_size(value.length, schema.array.len, this.fieldPath); - } else { - this.encoded.store_value(value.length, "u32"); - } - for (var i = 0; i < value.length; i++) { - this.encode_value(value[i], schema.array.type); - } - }; - BorshSerializer2.prototype.encode_buffer = function(value, schema) { - if (schema.array.len) { - expect_same_size(value.byteLength, schema.array.len, this.fieldPath); - } else { - this.encoded.store_value(value.byteLength, "u32"); - } - this.encoded.store_bytes(new Uint8Array(value)); - }; - BorshSerializer2.prototype.encode_set = function(value, schema) { - this.checkTypes && expect_type(value, "object", this.fieldPath); - var isSet = value instanceof Set; - var values = isSet ? Array.from(value.values()) : Object.values(value); - this.encoded.store_value(values.length, "u32"); - for (var _i = 0, values_1 = values; _i < values_1.length; _i++) { - var value_1 = values_1[_i]; - this.encode_value(value_1, schema.set); - } - }; - BorshSerializer2.prototype.encode_map = function(value, schema) { - this.checkTypes && expect_type(value, "object", this.fieldPath); - var isMap = value instanceof Map; - var keys = isMap ? Array.from(value.keys()) : Object.keys(value); - this.encoded.store_value(keys.length, "u32"); - for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) { - var key = keys_1[_i]; - this.encode_value(key, schema.map.key); - this.encode_value(isMap ? value.get(key) : value[key], schema.map.value); - } - }; - BorshSerializer2.prototype.encode_struct = function(value, schema) { - this.checkTypes && expect_type(value, "object", this.fieldPath); - for (var _i = 0, _a = Object.keys(schema.struct); _i < _a.length; _i++) { - var key = _a[_i]; - this.fieldPath.push(key); - this.encode_value(value[key], schema.struct[key]); - this.fieldPath.pop(); - } - }; - return BorshSerializer2; - }() - ); - - // ../../node_modules/borsh/lib/esm/deserialize.js - var BorshDeserializer = ( - /** @class */ - function() { - function BorshDeserializer2(bufferArray) { - this.buffer = new DecodeBuffer(bufferArray); - } - __name(BorshDeserializer2, "BorshDeserializer"); - BorshDeserializer2.prototype.decode = function(schema) { - return this.decode_value(schema); - }; - BorshDeserializer2.prototype.decode_value = function(schema) { - if (typeof schema === "string") { - if (integers.includes(schema)) - return this.decode_integer(schema); - if (schema === "string") - return this.decode_string(); - if (schema === "bool") - return this.decode_boolean(); - } - if (typeof schema === "object") { - if ("option" in schema) - return this.decode_option(schema); - if ("enum" in schema) - return this.decode_enum(schema); - if ("array" in schema) - return this.decode_array(schema); - if ("set" in schema) - return this.decode_set(schema); - if ("map" in schema) - return this.decode_map(schema); - if ("struct" in schema) - return this.decode_struct(schema); - } - throw new Error("Unsupported type: ".concat(schema)); - }; - BorshDeserializer2.prototype.decode_integer = function(schema) { - var size = parseInt(schema.substring(1)); - if (size <= 32 || schema == "f64") { - return this.buffer.consume_value(schema); - } - return this.decode_bigint(size, schema.startsWith("i")); - }; - BorshDeserializer2.prototype.decode_bigint = function(size, signed) { - if (signed === void 0) { - signed = false; - } - var buffer_len = size / 8; - var buffer = new Uint8Array(this.buffer.consume_bytes(buffer_len)); - var bits = buffer.reduceRight(function(r, x) { - return r + x.toString(16).padStart(2, "0"); - }, ""); - if (signed && buffer[buffer_len - 1]) { - return BigInt.asIntN(size, BigInt("0x".concat(bits))); - } - return BigInt("0x".concat(bits)); - }; - BorshDeserializer2.prototype.decode_string = function() { - var len = this.decode_integer("u32"); - var buffer = new Uint8Array(this.buffer.consume_bytes(len)); - var codePoints = []; - for (var i = 0; i < len; ++i) { - var byte = buffer[i]; - if (byte < 128) { - codePoints.push(byte); - } else if (byte < 224) { - codePoints.push((byte & 31) << 6 | buffer[++i] & 63); - } else if (byte < 240) { - codePoints.push((byte & 15) << 12 | (buffer[++i] & 63) << 6 | buffer[++i] & 63); - } else { - var codePoint = (byte & 7) << 18 | (buffer[++i] & 63) << 12 | (buffer[++i] & 63) << 6 | buffer[++i] & 63; - codePoints.push(codePoint); - } - } - return String.fromCodePoint.apply(String, codePoints); - }; - BorshDeserializer2.prototype.decode_boolean = function() { - return this.buffer.consume_value("u8") > 0; - }; - BorshDeserializer2.prototype.decode_option = function(schema) { - var option = this.buffer.consume_value("u8"); - if (option === 1) { - return this.decode_value(schema.option); - } - if (option !== 0) { - throw new Error("Invalid option ".concat(option)); - } - return null; - }; - BorshDeserializer2.prototype.decode_enum = function(schema) { - var _a; - var valueIndex = this.buffer.consume_value("u8"); - if (valueIndex > schema["enum"].length) { - throw new Error("Enum option ".concat(valueIndex, " is not available")); - } - var struct = schema["enum"][valueIndex].struct; - var key = Object.keys(struct)[0]; - return _a = {}, _a[key] = this.decode_value(struct[key]), _a; - }; - BorshDeserializer2.prototype.decode_array = function(schema) { - var result = []; - var len = schema.array.len ? schema.array.len : this.decode_integer("u32"); - for (var i = 0; i < len; ++i) { - result.push(this.decode_value(schema.array.type)); - } - return result; - }; - BorshDeserializer2.prototype.decode_set = function(schema) { - var len = this.decode_integer("u32"); - var result = /* @__PURE__ */ new Set(); - for (var i = 0; i < len; ++i) { - result.add(this.decode_value(schema.set)); - } - return result; - }; - BorshDeserializer2.prototype.decode_map = function(schema) { - var len = this.decode_integer("u32"); - var result = /* @__PURE__ */ new Map(); - for (var i = 0; i < len; ++i) { - var key = this.decode_value(schema.map.key); - var value = this.decode_value(schema.map.value); - result.set(key, value); - } - return result; - }; - BorshDeserializer2.prototype.decode_struct = function(schema) { - var result = {}; - for (var key in schema.struct) { - result[key] = this.decode_value(schema.struct[key]); - } - return result; - }; - return BorshDeserializer2; - }() - ); - - // ../../node_modules/borsh/lib/esm/index.js - function serialize(schema, value, validate) { - if (validate === void 0) { - validate = true; - } - if (validate) - validate_schema(schema); - var serializer = new BorshSerializer(validate); - return serializer.encode(value, schema); - } - __name(serialize, "serialize"); - function deserialize(schema, buffer, validate) { - if (validate === void 0) { - validate = true; - } - if (validate) - validate_schema(schema); - var deserializer = new BorshDeserializer(buffer); - return deserializer.decode(schema); - } - __name(deserialize, "deserialize"); - - // ../borsh-schema/src/index.ts - var src_exports = {}; - __export(src_exports, { - getBorshSchema: () => getBorshSchema, - nearChainSchema: () => nearChainSchema - }); - var nearChainSchema = new class BorshSchema { - static { - __name(this, "BorshSchema"); - } - Ed25519Signature = { - struct: { - data: { array: { type: "u8", len: 64 } } - } - }; - Secp256k1Signature = { - struct: { - data: { array: { type: "u8", len: 65 } } - } - }; - Signature = { - enum: [ - { struct: { ed25519Signature: this.Ed25519Signature } }, - { struct: { secp256k1Signature: this.Secp256k1Signature } } - ] - }; - Ed25519Data = { - struct: { - data: { array: { type: "u8", len: 32 } } - } - }; - Secp256k1Data = { - struct: { - data: { array: { type: "u8", len: 64 } } - } - }; - PublicKey = { - enum: [ - { struct: { ed25519Key: this.Ed25519Data } }, - { struct: { secp256k1Key: this.Secp256k1Data } } - ] - }; - FunctionCallPermission = { - struct: { - allowance: { option: "u128" }, - receiverId: "string", - methodNames: { array: { type: "string" } } - } - }; - FullAccessPermission = { - struct: {} - }; - AccessKeyPermission = { - enum: [ - { struct: { functionCall: this.FunctionCallPermission } }, - { struct: { fullAccess: this.FullAccessPermission } } - ] - }; - AccessKey = { - struct: { - nonce: "u64", - permission: this.AccessKeyPermission - } - }; - CreateAccount = { - struct: {} - }; - DeployContract = { - struct: { - code: { array: { type: "u8" } } - } - }; - FunctionCall = { - struct: { - methodName: "string", - args: { array: { type: "u8" } }, - gas: "u64", - deposit: "u128" - } - }; - Transfer = { - struct: { - deposit: "u128" - } - }; - Stake = { - struct: { - stake: "u128", - publicKey: this.PublicKey - } - }; - AddKey = { - struct: { - publicKey: this.PublicKey, - accessKey: this.AccessKey - } - }; - DeleteKey = { - struct: { - publicKey: this.PublicKey - } - }; - DeleteAccount = { - struct: { - beneficiaryId: "string" - } - }; - ClassicAction = { - enum: [ - { struct: { createAccount: this.CreateAccount } }, - { struct: { deployContract: this.DeployContract } }, - { struct: { functionCall: this.FunctionCall } }, - { struct: { transfer: this.Transfer } }, - { struct: { stake: this.Stake } }, - { struct: { addKey: this.AddKey } }, - { struct: { deleteKey: this.DeleteKey } }, - { struct: { deleteAccount: this.DeleteAccount } } - ] - }; - DelegateAction = { - struct: { - senderId: "string", - receiverId: "string", - actions: { array: { type: this.ClassicAction } }, - nonce: "u64", - maxBlockHeight: "u64", - publicKey: this.PublicKey - } - }; - SignedDelegate = { - struct: { - delegateAction: this.DelegateAction, - signature: this.Signature - } - }; - Action = { - enum: [ - { struct: { createAccount: this.CreateAccount } }, - { struct: { deployContract: this.DeployContract } }, - { struct: { functionCall: this.FunctionCall } }, - { struct: { transfer: this.Transfer } }, - { struct: { stake: this.Stake } }, - { struct: { addKey: this.AddKey } }, - { struct: { deleteKey: this.DeleteKey } }, - { struct: { deleteAccount: this.DeleteAccount } }, - { struct: { signedDelegate: this.SignedDelegate } } - ] - }; - Transaction = { - struct: { - signerId: "string", - publicKey: this.PublicKey, - nonce: "u64", - receiverId: "string", - blockHash: { array: { type: "u8", len: 32 } }, - actions: { array: { type: this.Action } } - } - }; - SignedTransaction = { - struct: { - transaction: this.Transaction, - signature: this.Signature - } - }; - }(); - var getBorshSchema = /* @__PURE__ */ __name(() => nearChainSchema, "getBorshSchema"); - - // ../utils/src/transaction.ts - var txToJson = /* @__PURE__ */ __name((tx) => { - return JSON.parse(JSON.stringify( - tx, - (key, value) => typeof value === "bigint" ? value.toString() : value - )); - }, "txToJson"); - var txToJsonStringified = /* @__PURE__ */ __name((tx) => { - return JSON.stringify(txToJson(tx)); - }, "txToJsonStringified"); - function mapTransaction(jsonTransaction) { - return { - signerId: jsonTransaction.signerId, - publicKey: { - ed25519Key: { - data: keyFromString(jsonTransaction.publicKey) - } - }, - nonce: BigInt(jsonTransaction.nonce), - receiverId: jsonTransaction.receiverId, - blockHash: base58_to_binary_default(jsonTransaction.blockHash), - actions: jsonTransaction.actions.map(mapAction) - }; - } - __name(mapTransaction, "mapTransaction"); - function serializeTransaction(jsonTransaction) { - console.log("fastnear: serializing transaction"); - const transaction = mapTransaction(jsonTransaction); - console.log("fastnear: mapped transaction for borsh:", transaction); - return serialize(SCHEMA.Transaction, transaction); - } - __name(serializeTransaction, "serializeTransaction"); - function serializeSignedTransaction(jsonTransaction, signature) { - console.log("fastnear: Serializing Signed Transaction", jsonTransaction); - console.log("fastnear: signature", signature); - console.log("fastnear: signature length", base58_to_binary_default(signature).length); - const mappedSignedTx = mapTransaction(jsonTransaction); - console.log("fastnear: mapped (for borsh schema) signed transaction", mappedSignedTx); - const plainSignedTransaction = { - transaction: mappedSignedTx, - signature: { - ed25519Signature: { - data: base58_to_binary_default(signature) - } - } - }; - const borshSignedTx = serialize(SCHEMA.SignedTransaction, plainSignedTransaction, true); - console.log("fastnear: borsh-serialized signed transaction:", borshSignedTx); - return borshSignedTx; - } - __name(serializeSignedTransaction, "serializeSignedTransaction"); - function mapAction(action) { - switch (action.type) { - case "CreateAccount": { - return { - createAccount: {} - }; - } - case "DeployContract": { - return { - deployContract: { - code: base64ToBytes(action.codeBase64) - } - }; - } - case "FunctionCall": { - return { - functionCall: { - methodName: action.methodName, - args: action.argsBase64 !== null && action.argsBase64 !== void 0 ? base64ToBytes(action.argsBase64) : new TextEncoder().encode(JSON.stringify(action.args)), - gas: BigInt(action.gas ?? "300000000000000"), - deposit: BigInt(action.deposit ?? "0") - } - }; - } - case "Transfer": { - return { - transfer: { - deposit: BigInt(action.deposit) - } - }; - } - case "Stake": { - return { - stake: { - stake: BigInt(action.stake), - publicKey: { - ed25519Key: { - data: keyFromString(action.publicKey) - } - } - } - }; - } - case "AddKey": { - return { - addKey: { - publicKey: { - ed25519Key: { - data: keyFromString(action.publicKey) - } - }, - accessKey: { - nonce: BigInt(action.accessKey.nonce), - permission: action.accessKey.permission === "FullAccess" ? { fullAccess: {} } : { - functionCall: { - allowance: action.accessKey.allowance ? BigInt(action.accessKey.allowance) : null, - receiverId: action.accessKey.receiverId, - methodNames: action.accessKey.methodNames - } - } - } - } - }; - } - case "DeleteKey": { - return { - deleteKey: { - publicKey: { - ed25519Key: { - data: keyFromString(action.publicKey) - } - } - } - }; - } - case "DeleteAccount": { - return { - deleteAccount: { - beneficiaryId: action.beneficiaryId - } - }; - } - case "SignedDelegate": { - return { - signedDelegate: { - delegateAction: mapAction(action.delegateAction), - signature: { - ed25519Signature: base58_to_binary_default(action.signature) - } - } - }; - } - default: { - throw new Error("Not implemented action: " + action.type); - } - } - } - __name(mapAction, "mapAction"); - var SCHEMA = getBorshSchema(); - - // ../utils/src/index.ts - var exp = { - borsh: { - serialize, - deserialize - }, - borshSchema: src_exports - }; - - // src/state.ts - var state_exports = {}; - __export(state_exports, { - DEFAULT_NETWORK_ID: () => DEFAULT_NETWORK_ID, - NETWORKS: () => NETWORKS, - WIDGET_URL: () => WIDGET_URL, - _adapter: () => _adapter, - _config: () => _config, - _state: () => _state, - _txHistory: () => _txHistory, - _unbroadcastedEvents: () => _unbroadcastedEvents, - events: () => events, - getConfig: () => getConfig, - getTxHistory: () => getTxHistory, - getWalletAdapterState: () => getWalletAdapterState, - onAdapterStateUpdate: () => onAdapterStateUpdate, - resetTxHistory: () => resetTxHistory, - setConfig: () => setConfig, - update: () => update, - updateTxHistory: () => updateTxHistory - }); - - // ../wallet-adapter/src/index.ts - var WalletAdapter = class _WalletAdapter { - static { - __name(this, "WalletAdapter"); - } - /** @type {HTMLIFrameElement} */ - #iframe = null; - /** @type {string} */ - #targetOrigin; - /** @type {string} */ - #widgetUrl; - /** @type {Map} */ - #pending = /* @__PURE__ */ new Map(); - /** @type {WalletState} */ - #state; - /** @type {Function} */ - #onStateUpdate; - /** @type {string} */ - #callbackUrl; - /** @type {string} */ - static defaultWidgetUrl = "https://wallet-adapter.fastnear.com"; - /** - * @param {WalletAdapterConfig} [config] - */ - constructor({ - widgetUrl = _WalletAdapter.defaultWidgetUrl, - targetOrigin = "*", - onStateUpdate, - lastState, - callbackUrl = window.location.href - } = {}) { - this.#targetOrigin = targetOrigin; - this.#widgetUrl = widgetUrl; - this.#onStateUpdate = onStateUpdate; - this.#callbackUrl = callbackUrl; - this.#state = lastState || {}; - window.addEventListener("message", this.#handleMessage.bind(this)); - } - /** - * Creates an iframe for wallet interaction - * @param {string} path - Path to load in iframe - * @returns {HTMLIFrameElement} - */ - #createIframe(path) { - if (this.#iframe) { - this.#iframe.remove(); - } - const url = new URL(path, this.#widgetUrl); - const iframe = document.createElement("iframe"); - iframe.src = url.toString(); - iframe.allow = "usb"; - iframe.style.border = "none"; - iframe.style.zIndex = "10000"; - iframe.style.position = "fixed"; - iframe.style.display = "block"; - iframe.style.top = "0"; - iframe.style.left = "0"; - iframe.style.width = "100%"; - iframe.style.height = "100%"; - document.body.appendChild(iframe); - this.#iframe = iframe; - return iframe; - } - /** - * Handles messages from the wallet widget - * @param {MessageEvent} event - */ - #handleMessage(event2) { - if (this.#targetOrigin !== "*" && event2.origin !== this.#targetOrigin) { - return; - } - const { id, type, action, payload } = event2.data; - if (type !== "wallet-adapter") return; - if (action === "close") { - this.#iframe?.remove(); - this.#iframe = null; - return; - } - if (payload?.state) { - this.#state = { ...this.#state, ...payload.state }; - this.#onStateUpdate?.(this.#state); - } - const resolve = this.#pending.get(id); - if (resolve) { - this.#pending.delete(id); - this.#iframe?.remove(); - this.#iframe = null; - resolve(payload); - } - } - /** - * Sends a message to the wallet widget - * @param {string} path - Path to load in iframe - * @param {string} method - Method to call - * @param {Object} params - Parameters to pass - * @returns {Promise} - */ - async #sendMessage(path, method, params) { - return new Promise((resolve) => { - const id = Math.random().toString(36).slice(2); - this.#pending.set(id, resolve); - const iframe = this.#createIframe(path); - iframe.onload = () => { - iframe.contentWindow?.postMessage( - { - type: "wallet-adapter", - method, - params: { - id, - ...params, - state: this.#state, - callbackUrl: params.callbackUrl || this.#callbackUrl - } - }, - this.#targetOrigin - ); - }; - }); - } - /** - * Get current wallet state - * @returns {WalletState} - */ - getState() { - return { ...this.#state }; - } - /** - * Set current wallet state - * @param state - */ - setState(state2) { - this.#state = state2; - } - /** - * Sign in with a NEAR wallet - * @param {SignInConfig} config - * @returns {Promise} - * - * Should be returning SignInResult - */ - async signIn(config2) { - return this.#sendMessage("/login.html", "signIn", config2); - } - /** - * Send a transaction using connected wallet - * @param {TransactionConfig} config - * @returns {Promise} - */ - async sendTransactions(config2) { - return this.#sendMessage("/send.html", "sendTransactions", config2); - } - /** - * Clean up adapter resources - */ - destroy() { - window.removeEventListener("message", this.#handleMessage); - this.#iframe?.remove(); - this.#iframe = null; - } - }; - - // src/state.ts - var WIDGET_URL = "https://js.cdn.fastnear.com"; - var DEFAULT_NETWORK_ID = "mainnet"; - var NETWORKS = { - testnet: { - networkId: "testnet", - nodeUrl: "https://rpc.testnet.fastnear.com/" - }, - mainnet: { - networkId: "mainnet", - nodeUrl: "https://rpc.mainnet.fastnear.com/" - } - }; - var _config = lsGet("config") || { - ...NETWORKS[DEFAULT_NETWORK_ID] - }; - var _state = lsGet("state") || {}; - var onAdapterStateUpdate = /* @__PURE__ */ __name((state2) => { - console.log("Adapter state update:", state2); - const { accountId: accountId2, lastWalletId, privateKey } = state2; - update({ - accountId: accountId2 || void 0, - lastWalletId: lastWalletId || void 0, - ...privateKey ? { privateKey } : {} - }); - }, "onAdapterStateUpdate"); - var getWalletAdapterState = /* @__PURE__ */ __name(() => { - return { - publicKey: _state.publicKey, - accountId: _state.accountId, - lastWalletId: _state.lastWalletId, - networkId: _config.networkId - }; - }, "getWalletAdapterState"); - var _adapter = new WalletAdapter({ - onStateUpdate: onAdapterStateUpdate, - lastState: getWalletAdapterState(), - widgetUrl: WIDGET_URL - }); - try { - _state.publicKey = _state.privateKey ? publicKeyFromPrivate(_state.privateKey) : null; - } catch (e) { - console.error("Error parsing private key:", e); - _state.privateKey = null; - lsSet("nonce", null); - } - var _txHistory = lsGet("txHistory") || {}; - var _unbroadcastedEvents = { - account: [], - tx: [] - }; - var events = { - _eventListeners: { - account: /* @__PURE__ */ new Set(), - tx: /* @__PURE__ */ new Set() - }, - notifyAccountListeners: /* @__PURE__ */ __name((accountId2) => { - if (events._eventListeners.account.size === 0) { - _unbroadcastedEvents.account.push(accountId2); - return; - } - events._eventListeners.account.forEach((callback) => { - try { - callback(accountId2); - } catch (e) { - console.error(e); - } - }); - }, "notifyAccountListeners"), - notifyTxListeners: /* @__PURE__ */ __name((tx) => { - if (events._eventListeners.tx.size === 0) { - _unbroadcastedEvents.tx.push(tx); - return; - } - events._eventListeners.tx.forEach((callback) => { - try { - callback(tx); - } catch (e) { - console.error(e); - } - }); - }, "notifyTxListeners"), - onAccount: /* @__PURE__ */ __name((callback) => { - events._eventListeners.account.add(callback); - if (_unbroadcastedEvents.account.length > 0) { - const accountEvent = _unbroadcastedEvents.account; - _unbroadcastedEvents.account = []; - accountEvent.forEach(events.notifyAccountListeners); - } - }, "onAccount"), - onTx: /* @__PURE__ */ __name((callback) => { - events._eventListeners.tx.add(callback); - if (_unbroadcastedEvents.tx.length > 0) { - const txEvent = _unbroadcastedEvents.tx; - _unbroadcastedEvents.tx = []; - txEvent.forEach(events.notifyTxListeners); - } - }, "onTx") - }; - var update = /* @__PURE__ */ __name((newState) => { - const oldState = _state; - _state = { ..._state, ...newState }; - lsSet("state", { - accountId: _state.accountId, - privateKey: _state.privateKey, - lastWalletId: _state.lastWalletId, - accessKeyContractId: _state.accessKeyContractId - }); - if (newState.hasOwnProperty("privateKey") && newState.privateKey !== oldState.privateKey) { - _state.publicKey = newState.privateKey ? publicKeyFromPrivate(newState.privateKey) : null; - lsSet("nonce", null); - } - if (newState.accountId !== oldState.accountId) { - events.notifyAccountListeners(newState.accountId); - } - if (newState.hasOwnProperty("lastWalletId") && newState.lastWalletId !== oldState.lastWalletId || newState.hasOwnProperty("accountId") && newState.accountId !== oldState.accountId || newState.hasOwnProperty("privateKey") && newState.privateKey !== oldState.privateKey) { - _adapter.setState(getWalletAdapterState()); - } - }, "update"); - var updateTxHistory = /* @__PURE__ */ __name((txStatus) => { - const txId = txStatus.txId; - _txHistory[txId] = { - ..._txHistory[txId] || {}, - ...txStatus, - updateTimestamp: Date.now() - }; - lsSet("txHistory", _txHistory); - events.notifyTxListeners(_txHistory[txId]); - }, "updateTxHistory"); - var getConfig = /* @__PURE__ */ __name(() => { - return _config; - }, "getConfig"); - var getTxHistory = /* @__PURE__ */ __name(() => { - return _txHistory; - }, "getTxHistory"); - var setConfig = /* @__PURE__ */ __name((newConf) => { - _config = { ...NETWORKS[newConf.networkId], ...newConf }; - lsSet("config", _config); - }, "setConfig"); - var resetTxHistory = /* @__PURE__ */ __name(() => { - _txHistory = {}; - lsSet("txHistory", _txHistory); - }, "resetTxHistory"); - - // src/near.ts - big_default.DP = 27; - var MaxBlockDelayMs = 1e3 * 60 * 60 * 6; - function withBlockId(params, blockId) { - if (blockId === "final" || blockId === "optimistic") { - return { ...params, finality: blockId }; - } - return blockId ? { ...params, block_id: blockId } : { ...params, finality: "optimistic" }; - } - __name(withBlockId, "withBlockId"); - async function sendRpc(method, params) { - const config2 = getConfig(); - if (!config2?.nodeUrl) { - throw new Error("fastnear: getConfig() returned invalid config: missing nodeUrl."); - } - const response = await fetch(config2.nodeUrl, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - jsonrpc: "2.0", - id: `fastnear-${Date.now()}`, - method, - params - }) - }); - const result = await response.json(); - if (result.error) { - throw new Error(JSON.stringify(result.error)); - } - return result; - } - __name(sendRpc, "sendRpc"); - function afterTxSent(txId) { - const txHistory = getTxHistory(); - sendRpc("tx", { - tx_hash: txHistory[txId]?.txHash, - sender_account_id: txHistory[txId]?.tx?.signerId, - wait_until: "EXECUTED_OPTIMISTIC" - }).then((result) => { - const successValue = result?.result?.status?.SuccessValue; - updateTxHistory({ - txId, - status: "Executed", - result, - successValue: successValue ? tryParseJson(fromBase64(successValue)) : void 0, - finalState: true - }); - }).catch((error) => { - updateTxHistory({ - txId, - status: "ErrorAfterIncluded", - error: tryParseJson(error.message) ?? error.message, - finalState: true - }); - }); - } - __name(afterTxSent, "afterTxSent"); - async function sendTxToRpc(signedTxBase64, waitUntil, txId) { - waitUntil = waitUntil || "INCLUDED"; - try { - const sendTxRes = await sendRpc("send_tx", { - signed_tx_base64: signedTxBase64, - wait_until: waitUntil - }); - updateTxHistory({ txId, status: "Included", finalState: false }); - afterTxSent(txId); - return sendTxRes; - } catch (error) { - const errorMessage = error instanceof Error ? error.message : "Unknown error"; - updateTxHistory({ - txId, - status: "Error", - error: tryParseJson(errorMessage) ?? errorMessage, - finalState: false - }); - throw new Error(errorMessage); - } - } - __name(sendTxToRpc, "sendTxToRpc"); - function generateTxId() { - const randomPart = crypto.getRandomValues(new Uint32Array(2)).join(""); - return `tx-${Date.now()}-${parseInt(randomPart, 10).toString(36)}`; - } - __name(generateTxId, "generateTxId"); - var accountId = /* @__PURE__ */ __name(() => _state.accountId, "accountId"); - var publicKey = /* @__PURE__ */ __name(() => _state.publicKey, "publicKey"); - var config = /* @__PURE__ */ __name((newConfig) => { - const current = getConfig(); - if (newConfig) { - if (newConfig.networkId && current.networkId !== newConfig.networkId) { - setConfig(newConfig.networkId); - update({ accountId: null, privateKey: null, lastWalletId: null }); - lsSet("block", null); - resetTxHistory(); - } - setConfig({ ...getConfig(), ...newConfig }); - } - return getConfig(); - }, "config"); - var authStatus = /* @__PURE__ */ __name(() => { - if (!_state.accountId) { - return "SignedOut"; - } - return "SignedIn"; - }, "authStatus"); - var getPublicKeyForContract = /* @__PURE__ */ __name((opts) => { - return publicKey(); - }, "getPublicKeyForContract"); - var selected = /* @__PURE__ */ __name(() => { - const network = getConfig().networkId; - const nodeUrl = getConfig().nodeUrl; - const walletUrl = getConfig().walletUrl; - const helperUrl = getConfig().helperUrl; - const explorerUrl = getConfig().explorerUrl; - const account = accountId(); - const contract = _state.accessKeyContractId; - const publicKey2 = getPublicKeyForContract(); - return { - network, - nodeUrl, - walletUrl, - helperUrl, - explorerUrl, - account, - contract, - publicKey: publicKey2 - }; - }, "selected"); - var requestSignIn = /* @__PURE__ */ __name(async ({ contractId }) => { - const privateKey = privateKeyFromRandom(); - update({ accessKeyContractId: contractId, accountId: null, privateKey }); - const pubKey = publicKeyFromPrivate(privateKey); - const result = await _adapter.signIn({ - networkId: getConfig().networkId, - contractId, - publicKey: pubKey - }); - if (result.error) { - throw new Error(`Wallet error: ${result.error}`); - } - if (result.url) { - if (typeof window !== "undefined") { - setTimeout(() => { - window.location.href = result.url; - }, 100); - } - } else if (result.accountId) { - update({ accountId: result.accountId }); - } - }, "requestSignIn"); - var view = /* @__PURE__ */ __name(async ({ - contractId, - methodName, - args, - argsBase64, - blockId - }) => { - const encodedArgs = argsBase64 || (args ? toBase64(JSON.stringify(args)) : ""); - const queryResult = await sendRpc( - "query", - withBlockId( - { - request_type: "call_function", - account_id: contractId, - method_name: methodName, - args_base64: encodedArgs - }, - blockId - ) - ); - return parseJsonFromBytes(queryResult.result.result); - }, "view"); - var queryAccount = /* @__PURE__ */ __name(async ({ - accountId: accountId2, - blockId - }) => { - return sendRpc( - "query", - withBlockId({ request_type: "view_account", account_id: accountId2 }, blockId) - ); - }, "queryAccount"); - var queryBlock = /* @__PURE__ */ __name(async ({ blockId }) => { - return sendRpc("block", withBlockId({}, blockId)); - }, "queryBlock"); - var queryAccessKey = /* @__PURE__ */ __name(async ({ - accountId: accountId2, - publicKey: publicKey2, - blockId - }) => { - return sendRpc( - "query", - withBlockId( - { request_type: "view_access_key", account_id: accountId2, public_key: publicKey2 }, - blockId - ) - ); - }, "queryAccessKey"); - var queryTx = /* @__PURE__ */ __name(async ({ txHash, accountId: accountId2 }) => { - return sendRpc("tx", [txHash, accountId2]); - }, "queryTx"); - var localTxHistory = /* @__PURE__ */ __name(() => { - return getTxHistory(); - }, "localTxHistory"); - var signOut = /* @__PURE__ */ __name(() => { - update({ accountId: null, privateKey: null, contractId: null }); - setConfig(NETWORKS[DEFAULT_NETWORK_ID]); - }, "signOut"); - var sendTx = /* @__PURE__ */ __name(async ({ - receiverId, - actions: actions2, - waitUntil - }) => { - const signerId = _state.accountId; - if (!signerId) throw new Error("Must sign in"); - const publicKey2 = _state.publicKey ?? ""; - const privKey = _state.privateKey; - const txId = generateTxId(); - if (!privKey || receiverId !== _state.accessKeyContractId || !canSignWithLAK(actions2)) { - const jsonTx = { signerId, receiverId, actions: actions2 }; - updateTxHistory({ status: "Pending", txId, tx: jsonTx, finalState: false }); - const url = new URL(typeof window !== "undefined" ? window.location.href : ""); - url.searchParams.set("txIds", txId); - const existingParams = new URLSearchParams(window.location.search); - existingParams.forEach((value, key) => { - if (!url.searchParams.has(key)) { - url.searchParams.set(key, value); - } - }); - url.searchParams.delete("errorCode"); - url.searchParams.delete("errorMessage"); - try { - const result = await _adapter.sendTransactions({ - transactions: [jsonTx], - callbackUrl: url.toString() - }); - if (result.url) { - if (typeof window !== "undefined") { - setTimeout(() => { - window.location.href = result.url; - }, 100); - } - } else if (result.outcomes?.length) { - result.outcomes.forEach( - (r) => updateTxHistory({ - txId, - status: "Executed", - result: r, - txHash: r.transaction.hash, - finalState: true - }) - ); - } else if (result.rejected) { - updateTxHistory({ txId, status: "RejectedByUser", finalState: true }); - } else if (result.error) { - updateTxHistory({ - txId, - status: "Error", - error: tryParseJson(result.error), - finalState: true - }); - } - return result; - } catch (err) { - console.error("fastnear: error sending tx using adapter:", err); - updateTxHistory({ - txId, - status: "Error", - error: tryParseJson(err.message), - finalState: true - }); - return Promise.reject(err); - } - } - let nonce = lsGet("nonce"); - if (nonce == null) { - const accessKey = await queryAccessKey({ accountId: signerId, publicKey: publicKey2 }); - if (accessKey.result.error) { - throw new Error(`Access key error: ${accessKey.result.error} when attempting to get nonce for ${signerId} for public key ${publicKey2}`); - } - nonce = accessKey.result.nonce; - lsSet("nonce", nonce); - } - let lastKnownBlock = lsGet("block"); - if (!lastKnownBlock || parseFloat(lastKnownBlock.header.timestamp_nanosec) / 1e6 + MaxBlockDelayMs < Date.now()) { - const latestBlock = await queryBlock({ blockId: "final" }); - lastKnownBlock = { - header: { - hash: latestBlock.result.header.hash, - timestamp_nanosec: latestBlock.result.header.timestamp_nanosec - } - }; - lsSet("block", lastKnownBlock); - } - nonce += 1; - lsSet("nonce", nonce); - const blockHash = lastKnownBlock.header.hash; - const plainTransactionObj = { - signerId, - publicKey: publicKey2, - nonce, - receiverId, - blockHash, - actions: actions2 - }; - const txBytes = serializeTransaction(plainTransactionObj); - const txHashBytes = sha256(txBytes); - const txHash58 = binary_to_base58_default(txHashBytes); - const signatureBase58 = signHash(txHashBytes, privKey, { returnBase58: true }); - const signedTransactionBytes = serializeSignedTransaction(plainTransactionObj, signatureBase58); - const signedTxBase64 = bytesToBase64(signedTransactionBytes); - updateTxHistory({ - status: "Pending", - txId, - tx: plainTransactionObj, - signature: signatureBase58, - signedTxBase64, - txHash: txHash58, - finalState: false - }); - try { - return await sendTxToRpc(signedTxBase64, waitUntil, txId); - } catch (error) { - console.error("Error Sending Transaction:", error, plainTransactionObj, signedTxBase64); - } - }, "sendTx"); - var exp2 = { - utils: {}, - // we will map this in a moment, giving keys, for IDE hints - borsh: exp.borsh, - borshSchema: exp.borshSchema.getBorshSchema() - }; - for (const key in src_exports2) { - exp2.utils[key] = src_exports2[key]; - } - var utils = exp2.utils; - var state = {}; - for (const key in state_exports) { - state[key] = state_exports[key]; - } - var event = state["events"]; - delete state["events"]; - try { - if (typeof window !== "undefined") { - const url = new URL(window.location.href); - const accId = url.searchParams.get("account_id"); - const pubKey = url.searchParams.get("public_key"); - const errCode = url.searchParams.get("errorCode"); - const errMsg = url.searchParams.get("errorMessage"); - const decodedErrMsg = errMsg ? decodeURIComponent(errMsg) : null; - const txHashes = url.searchParams.get("transactionHashes"); - const txIds = url.searchParams.get("txIds"); - if (errCode || errMsg) { - console.warn(new Error(`Wallet raises: -code: ${errCode} -message: ${decodedErrMsg}`)); - } - if (accId && pubKey) { - if (pubKey === _state.publicKey) { - update({ accountId: accId }); - } else { - if (authStatus() === "SignedIn") { - console.warn("Public key mismatch from wallet redirect", pubKey, _state.publicKey); - } - url.searchParams.delete("public_key"); - } - } - if (txHashes || txIds) { - const hashArr = txHashes ? txHashes.split(",") : []; - const idArr = txIds ? txIds.split(",") : []; - if (idArr.length > hashArr.length) { - idArr.forEach((id) => { - updateTxHistory({ txId: id, status: "RejectedByUser", finalState: true }); - }); - } else if (idArr.length === hashArr.length) { - idArr.forEach((id, i) => { - updateTxHistory({ - txId: id, - status: "PendingGotTxHash", - txHash: hashArr[i], - finalState: false - }); - afterTxSent(id); - }); - } else { - console.error(new Error("Transaction hash mismatch from wallet redirect"), idArr, hashArr); - } - } - url.searchParams.delete("txIds"); - if (authStatus() === "SignedOut") { - url.searchParams.delete("errorCode"); - url.searchParams.delete("errorMessage"); - } - } - } catch (e) { - console.error("Error handling wallet redirect:", e); - } - var actions = { - functionCall: /* @__PURE__ */ __name(({ - methodName, - gas, - deposit, - args, - argsBase64 - }) => ({ - type: "FunctionCall", - methodName, - args, - argsBase64, - gas, - deposit - }), "functionCall"), - transfer: /* @__PURE__ */ __name((yoctoAmount) => ({ - type: "Transfer", - deposit: yoctoAmount - }), "transfer"), - stakeNEAR: /* @__PURE__ */ __name(({ amount, publicKey: publicKey2 }) => ({ - type: "Stake", - stake: amount, - publicKey: publicKey2 - }), "stakeNEAR"), - addFullAccessKey: /* @__PURE__ */ __name(({ publicKey: publicKey2 }) => ({ - type: "AddKey", - publicKey: publicKey2, - accessKey: { permission: "FullAccess" } - }), "addFullAccessKey"), - addLimitedAccessKey: /* @__PURE__ */ __name(({ - publicKey: publicKey2, - allowance, - accountId: accountId2, - methodNames - }) => ({ - type: "AddKey", - publicKey: publicKey2, - accessKey: { - permission: "FunctionCall", - allowance, - receiverId: accountId2, - methodNames - } - }), "addLimitedAccessKey"), - deleteKey: /* @__PURE__ */ __name(({ publicKey: publicKey2 }) => ({ - type: "DeleteKey", - publicKey: publicKey2 - }), "deleteKey"), - deleteAccount: /* @__PURE__ */ __name(({ beneficiaryId }) => ({ - type: "DeleteAccount", - beneficiaryId - }), "deleteAccount"), - createAccount: /* @__PURE__ */ __name(() => ({ - type: "CreateAccount" - }), "createAccount"), - deployContract: /* @__PURE__ */ __name(({ codeBase64 }) => ({ - type: "DeployContract", - codeBase64 - }), "deployContract") - }; - return __toCommonJS(src_exports3); -})(); -/*! Bundled license information: - -@noble/hashes/esm/utils.js: - (*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *) - -@noble/curves/esm/abstract/utils.js: - (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *) - -@noble/curves/esm/abstract/modular.js: - (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *) - -@noble/curves/esm/abstract/curve.js: - (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *) - -@noble/curves/esm/abstract/edwards.js: - (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *) - -@noble/curves/esm/ed25519.js: - (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *) -*/ - -try { - Object.defineProperty(globalThis, 'near', { - value: near, - enumerable: true, - configurable: false, - }); -} catch (error) { - console.error('Could not define global "near" object', error); - throw error; -} - -window.$$ = near.utils.convertUnit; - -//# sourceMappingURL=browser.global.js.map diff --git a/static/js-loaded-globally/nearjs/0.9.7/umd/browser.global.js.map b/static/js-loaded-globally/nearjs/0.9.7/umd/browser.global.js.map deleted file mode 100644 index d7d9e1a..0000000 --- a/static/js-loaded-globally/nearjs/0.9.7/umd/browser.global.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["../../src/index.ts","../../../../node_modules/big.js/big.mjs","../../../utils/src/index.ts","../../../../node_modules/@noble/hashes/src/_assert.ts","../../../../node_modules/@noble/hashes/src/crypto.ts","../../../../node_modules/@noble/hashes/src/utils.ts","../../../../node_modules/@noble/hashes/src/_md.ts","../../../../node_modules/@noble/hashes/src/_u64.ts","../../../../node_modules/@noble/hashes/src/sha512.ts","../../../../node_modules/@noble/curves/src/abstract/utils.ts","../../../../node_modules/@noble/curves/src/abstract/modular.ts","../../../../node_modules/@noble/curves/src/abstract/curve.ts","../../../../node_modules/@noble/curves/src/abstract/edwards.ts","../../../../node_modules/@noble/curves/src/ed25519.ts","../../../../node_modules/@noble/hashes/src/sha256.ts","../../../utils/node_modules/base58-js/base58_chars.js","../../../utils/node_modules/base58-js/base58_to_binary.js","../../../utils/node_modules/base58-js/create_base58_map.js","../../../utils/node_modules/base58-js/binary_to_base58.js","../../../../node_modules/js-base64/base64.mjs","../../../utils/src/storage.ts","../../../utils/src/misc.ts","../../../utils/src/crypto.ts","../../../../node_modules/borsh/lib/esm/types.js","../../../../node_modules/borsh/lib/esm/buffer.js","../../../../node_modules/borsh/lib/esm/utils.js","../../../../node_modules/borsh/lib/esm/serialize.js","../../../../node_modules/borsh/lib/esm/deserialize.js","../../../../node_modules/borsh/lib/esm/index.js","../../../borsh-schema/src/index.ts","../../../utils/src/transaction.ts","../../src/state.ts","../../../wallet-adapter/src/index.ts","../../src/near.ts"],"sourcesContent":["// See tsup.config.ts for additional banner/footer js\nexport * from \"./near.js\";\n","/*\r\n * big.js v6.2.2\r\n * A small, fast, easy-to-use library for arbitrary-precision decimal arithmetic.\r\n * Copyright (c) 2024 Michael Mclaughlin\r\n * https://github.com/MikeMcl/big.js/LICENCE.md\r\n */\r\n\r\n\r\n/************************************** EDITABLE DEFAULTS *****************************************/\r\n\r\n\r\n // The default values below must be integers within the stated ranges.\r\n\r\n /*\r\n * The maximum number of decimal places (DP) of the results of operations involving division:\r\n * div and sqrt, and pow with negative exponents.\r\n */\r\nvar DP = 20, // 0 to MAX_DP\r\n\r\n /*\r\n * The rounding mode (RM) used when rounding to the above decimal places.\r\n *\r\n * 0 Towards zero (i.e. truncate, no rounding). (ROUND_DOWN)\r\n * 1 To nearest neighbour. If equidistant, round up. (ROUND_HALF_UP)\r\n * 2 To nearest neighbour. If equidistant, to even. (ROUND_HALF_EVEN)\r\n * 3 Away from zero. (ROUND_UP)\r\n */\r\n RM = 1, // 0, 1, 2 or 3\r\n\r\n // The maximum value of DP and Big.DP.\r\n MAX_DP = 1E6, // 0 to 1000000\r\n\r\n // The maximum magnitude of the exponent argument to the pow method.\r\n MAX_POWER = 1E6, // 1 to 1000000\r\n\r\n /*\r\n * The negative exponent (NE) at and beneath which toString returns exponential notation.\r\n * (JavaScript numbers: -7)\r\n * -1000000 is the minimum recommended exponent value of a Big.\r\n */\r\n NE = -7, // 0 to -1000000\r\n\r\n /*\r\n * The positive exponent (PE) at and above which toString returns exponential notation.\r\n * (JavaScript numbers: 21)\r\n * 1000000 is the maximum recommended exponent value of a Big, but this limit is not enforced.\r\n */\r\n PE = 21, // 0 to 1000000\r\n\r\n /*\r\n * When true, an error will be thrown if a primitive number is passed to the Big constructor,\r\n * or if valueOf is called, or if toNumber is called on a Big which cannot be converted to a\r\n * primitive number without a loss of precision.\r\n */\r\n STRICT = false, // true or false\r\n\r\n\r\n/**************************************************************************************************/\r\n\r\n\r\n // Error messages.\r\n NAME = '[big.js] ',\r\n INVALID = NAME + 'Invalid ',\r\n INVALID_DP = INVALID + 'decimal places',\r\n INVALID_RM = INVALID + 'rounding mode',\r\n DIV_BY_ZERO = NAME + 'Division by zero',\r\n\r\n // The shared prototype object.\r\n P = {},\r\n UNDEFINED = void 0,\r\n NUMERIC = /^-?(\\d+(\\.\\d*)?|\\.\\d+)(e[+-]?\\d+)?$/i;\r\n\r\n\r\n/*\r\n * Create and return a Big constructor.\r\n */\r\nfunction _Big_() {\r\n\r\n /*\r\n * The Big constructor and exported function.\r\n * Create and return a new instance of a Big number object.\r\n *\r\n * n {number|string|Big} A numeric value.\r\n */\r\n function Big(n) {\r\n var x = this;\r\n\r\n // Enable constructor usage without new.\r\n if (!(x instanceof Big)) return n === UNDEFINED ? _Big_() : new Big(n);\r\n\r\n // Duplicate.\r\n if (n instanceof Big) {\r\n x.s = n.s;\r\n x.e = n.e;\r\n x.c = n.c.slice();\r\n } else {\r\n if (typeof n !== 'string') {\r\n if (Big.strict === true && typeof n !== 'bigint') {\r\n throw TypeError(INVALID + 'value');\r\n }\r\n\r\n // Minus zero?\r\n n = n === 0 && 1 / n < 0 ? '-0' : String(n);\r\n }\r\n\r\n parse(x, n);\r\n }\r\n\r\n // Retain a reference to this Big constructor.\r\n // Shadow Big.prototype.constructor which points to Object.\r\n x.constructor = Big;\r\n }\r\n\r\n Big.prototype = P;\r\n Big.DP = DP;\r\n Big.RM = RM;\r\n Big.NE = NE;\r\n Big.PE = PE;\r\n Big.strict = STRICT;\r\n Big.roundDown = 0;\r\n Big.roundHalfUp = 1;\r\n Big.roundHalfEven = 2;\r\n Big.roundUp = 3;\r\n\r\n return Big;\r\n}\r\n\r\n\r\n/*\r\n * Parse the number or string value passed to a Big constructor.\r\n *\r\n * x {Big} A Big number instance.\r\n * n {number|string} A numeric value.\r\n */\r\nfunction parse(x, n) {\r\n var e, i, nl;\r\n\r\n if (!NUMERIC.test(n)) {\r\n throw Error(INVALID + 'number');\r\n }\r\n\r\n // Determine sign.\r\n x.s = n.charAt(0) == '-' ? (n = n.slice(1), -1) : 1;\r\n\r\n // Decimal point?\r\n if ((e = n.indexOf('.')) > -1) n = n.replace('.', '');\r\n\r\n // Exponential form?\r\n if ((i = n.search(/e/i)) > 0) {\r\n\r\n // Determine exponent.\r\n if (e < 0) e = i;\r\n e += +n.slice(i + 1);\r\n n = n.substring(0, i);\r\n } else if (e < 0) {\r\n\r\n // Integer.\r\n e = n.length;\r\n }\r\n\r\n nl = n.length;\r\n\r\n // Determine leading zeros.\r\n for (i = 0; i < nl && n.charAt(i) == '0';) ++i;\r\n\r\n if (i == nl) {\r\n\r\n // Zero.\r\n x.c = [x.e = 0];\r\n } else {\r\n\r\n // Determine trailing zeros.\r\n for (; nl > 0 && n.charAt(--nl) == '0';);\r\n x.e = e - i - 1;\r\n x.c = [];\r\n\r\n // Convert string to array of digits without leading/trailing zeros.\r\n for (e = 0; i <= nl;) x.c[e++] = +n.charAt(i++);\r\n }\r\n\r\n return x;\r\n}\r\n\r\n\r\n/*\r\n * Round Big x to a maximum of sd significant digits using rounding mode rm.\r\n *\r\n * x {Big} The Big to round.\r\n * sd {number} Significant digits: integer, 0 to MAX_DP inclusive.\r\n * rm {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up).\r\n * [more] {boolean} Whether the result of division was truncated.\r\n */\r\nfunction round(x, sd, rm, more) {\r\n var xc = x.c;\r\n\r\n if (rm === UNDEFINED) rm = x.constructor.RM;\r\n if (rm !== 0 && rm !== 1 && rm !== 2 && rm !== 3) {\r\n throw Error(INVALID_RM);\r\n }\r\n\r\n if (sd < 1) {\r\n more =\r\n rm === 3 && (more || !!xc[0]) || sd === 0 && (\r\n rm === 1 && xc[0] >= 5 ||\r\n rm === 2 && (xc[0] > 5 || xc[0] === 5 && (more || xc[1] !== UNDEFINED))\r\n );\r\n\r\n xc.length = 1;\r\n\r\n if (more) {\r\n\r\n // 1, 0.1, 0.01, 0.001, 0.0001 etc.\r\n x.e = x.e - sd + 1;\r\n xc[0] = 1;\r\n } else {\r\n\r\n // Zero.\r\n xc[0] = x.e = 0;\r\n }\r\n } else if (sd < xc.length) {\r\n\r\n // xc[sd] is the digit after the digit that may be rounded up.\r\n more =\r\n rm === 1 && xc[sd] >= 5 ||\r\n rm === 2 && (xc[sd] > 5 || xc[sd] === 5 &&\r\n (more || xc[sd + 1] !== UNDEFINED || xc[sd - 1] & 1)) ||\r\n rm === 3 && (more || !!xc[0]);\r\n\r\n // Remove any digits after the required precision.\r\n xc.length = sd;\r\n\r\n // Round up?\r\n if (more) {\r\n\r\n // Rounding up may mean the previous digit has to be rounded up.\r\n for (; ++xc[--sd] > 9;) {\r\n xc[sd] = 0;\r\n if (sd === 0) {\r\n ++x.e;\r\n xc.unshift(1);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // Remove trailing zeros.\r\n for (sd = xc.length; !xc[--sd];) xc.pop();\r\n }\r\n\r\n return x;\r\n}\r\n\r\n\r\n/*\r\n * Return a string representing the value of Big x in normal or exponential notation.\r\n * Handles P.toExponential, P.toFixed, P.toJSON, P.toPrecision, P.toString and P.valueOf.\r\n */\r\nfunction stringify(x, doExponential, isNonzero) {\r\n var e = x.e,\r\n s = x.c.join(''),\r\n n = s.length;\r\n\r\n // Exponential notation?\r\n if (doExponential) {\r\n s = s.charAt(0) + (n > 1 ? '.' + s.slice(1) : '') + (e < 0 ? 'e' : 'e+') + e;\r\n\r\n // Normal notation.\r\n } else if (e < 0) {\r\n for (; ++e;) s = '0' + s;\r\n s = '0.' + s;\r\n } else if (e > 0) {\r\n if (++e > n) {\r\n for (e -= n; e--;) s += '0';\r\n } else if (e < n) {\r\n s = s.slice(0, e) + '.' + s.slice(e);\r\n }\r\n } else if (n > 1) {\r\n s = s.charAt(0) + '.' + s.slice(1);\r\n }\r\n\r\n return x.s < 0 && isNonzero ? '-' + s : s;\r\n}\r\n\r\n\r\n// Prototype/instance methods\r\n\r\n\r\n/*\r\n * Return a new Big whose value is the absolute value of this Big.\r\n */\r\nP.abs = function () {\r\n var x = new this.constructor(this);\r\n x.s = 1;\r\n return x;\r\n};\r\n\r\n\r\n/*\r\n * Return 1 if the value of this Big is greater than the value of Big y,\r\n * -1 if the value of this Big is less than the value of Big y, or\r\n * 0 if they have the same value.\r\n */\r\nP.cmp = function (y) {\r\n var isneg,\r\n x = this,\r\n xc = x.c,\r\n yc = (y = new x.constructor(y)).c,\r\n i = x.s,\r\n j = y.s,\r\n k = x.e,\r\n l = y.e;\r\n\r\n // Either zero?\r\n if (!xc[0] || !yc[0]) return !xc[0] ? !yc[0] ? 0 : -j : i;\r\n\r\n // Signs differ?\r\n if (i != j) return i;\r\n\r\n isneg = i < 0;\r\n\r\n // Compare exponents.\r\n if (k != l) return k > l ^ isneg ? 1 : -1;\r\n\r\n j = (k = xc.length) < (l = yc.length) ? k : l;\r\n\r\n // Compare digit by digit.\r\n for (i = -1; ++i < j;) {\r\n if (xc[i] != yc[i]) return xc[i] > yc[i] ^ isneg ? 1 : -1;\r\n }\r\n\r\n // Compare lengths.\r\n return k == l ? 0 : k > l ^ isneg ? 1 : -1;\r\n};\r\n\r\n\r\n/*\r\n * Return a new Big whose value is the value of this Big divided by the value of Big y, rounded,\r\n * if necessary, to a maximum of Big.DP decimal places using rounding mode Big.RM.\r\n */\r\nP.div = function (y) {\r\n var x = this,\r\n Big = x.constructor,\r\n a = x.c, // dividend\r\n b = (y = new Big(y)).c, // divisor\r\n k = x.s == y.s ? 1 : -1,\r\n dp = Big.DP;\r\n\r\n if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {\r\n throw Error(INVALID_DP);\r\n }\r\n\r\n // Divisor is zero?\r\n if (!b[0]) {\r\n throw Error(DIV_BY_ZERO);\r\n }\r\n\r\n // Dividend is 0? Return +-0.\r\n if (!a[0]) {\r\n y.s = k;\r\n y.c = [y.e = 0];\r\n return y;\r\n }\r\n\r\n var bl, bt, n, cmp, ri,\r\n bz = b.slice(),\r\n ai = bl = b.length,\r\n al = a.length,\r\n r = a.slice(0, bl), // remainder\r\n rl = r.length,\r\n q = y, // quotient\r\n qc = q.c = [],\r\n qi = 0,\r\n p = dp + (q.e = x.e - y.e) + 1; // precision of the result\r\n\r\n q.s = k;\r\n k = p < 0 ? 0 : p;\r\n\r\n // Create version of divisor with leading zero.\r\n bz.unshift(0);\r\n\r\n // Add zeros to make remainder as long as divisor.\r\n for (; rl++ < bl;) r.push(0);\r\n\r\n do {\r\n\r\n // n is how many times the divisor goes into current remainder.\r\n for (n = 0; n < 10; n++) {\r\n\r\n // Compare divisor and remainder.\r\n if (bl != (rl = r.length)) {\r\n cmp = bl > rl ? 1 : -1;\r\n } else {\r\n for (ri = -1, cmp = 0; ++ri < bl;) {\r\n if (b[ri] != r[ri]) {\r\n cmp = b[ri] > r[ri] ? 1 : -1;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // If divisor < remainder, subtract divisor from remainder.\r\n if (cmp < 0) {\r\n\r\n // Remainder can't be more than 1 digit longer than divisor.\r\n // Equalise lengths using divisor with extra leading zero?\r\n for (bt = rl == bl ? b : bz; rl;) {\r\n if (r[--rl] < bt[rl]) {\r\n ri = rl;\r\n for (; ri && !r[--ri];) r[ri] = 9;\r\n --r[ri];\r\n r[rl] += 10;\r\n }\r\n r[rl] -= bt[rl];\r\n }\r\n\r\n for (; !r[0];) r.shift();\r\n } else {\r\n break;\r\n }\r\n }\r\n\r\n // Add the digit n to the result array.\r\n qc[qi++] = cmp ? n : ++n;\r\n\r\n // Update the remainder.\r\n if (r[0] && cmp) r[rl] = a[ai] || 0;\r\n else r = [a[ai]];\r\n\r\n } while ((ai++ < al || r[0] !== UNDEFINED) && k--);\r\n\r\n // Leading zero? Do not remove if result is simply zero (qi == 1).\r\n if (!qc[0] && qi != 1) {\r\n\r\n // There can't be more than one zero.\r\n qc.shift();\r\n q.e--;\r\n p--;\r\n }\r\n\r\n // Round?\r\n if (qi > p) round(q, p, Big.RM, r[0] !== UNDEFINED);\r\n\r\n return q;\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Big is equal to the value of Big y, otherwise return false.\r\n */\r\nP.eq = function (y) {\r\n return this.cmp(y) === 0;\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Big is greater than the value of Big y, otherwise return\r\n * false.\r\n */\r\nP.gt = function (y) {\r\n return this.cmp(y) > 0;\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Big is greater than or equal to the value of Big y, otherwise\r\n * return false.\r\n */\r\nP.gte = function (y) {\r\n return this.cmp(y) > -1;\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Big is less than the value of Big y, otherwise return false.\r\n */\r\nP.lt = function (y) {\r\n return this.cmp(y) < 0;\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Big is less than or equal to the value of Big y, otherwise\r\n * return false.\r\n */\r\nP.lte = function (y) {\r\n return this.cmp(y) < 1;\r\n};\r\n\r\n\r\n/*\r\n * Return a new Big whose value is the value of this Big minus the value of Big y.\r\n */\r\nP.minus = P.sub = function (y) {\r\n var i, j, t, xlty,\r\n x = this,\r\n Big = x.constructor,\r\n a = x.s,\r\n b = (y = new Big(y)).s;\r\n\r\n // Signs differ?\r\n if (a != b) {\r\n y.s = -b;\r\n return x.plus(y);\r\n }\r\n\r\n var xc = x.c.slice(),\r\n xe = x.e,\r\n yc = y.c,\r\n ye = y.e;\r\n\r\n // Either zero?\r\n if (!xc[0] || !yc[0]) {\r\n if (yc[0]) {\r\n y.s = -b;\r\n } else if (xc[0]) {\r\n y = new Big(x);\r\n } else {\r\n y.s = 1;\r\n }\r\n return y;\r\n }\r\n\r\n // Determine which is the bigger number. Prepend zeros to equalise exponents.\r\n if (a = xe - ye) {\r\n\r\n if (xlty = a < 0) {\r\n a = -a;\r\n t = xc;\r\n } else {\r\n ye = xe;\r\n t = yc;\r\n }\r\n\r\n t.reverse();\r\n for (b = a; b--;) t.push(0);\r\n t.reverse();\r\n } else {\r\n\r\n // Exponents equal. Check digit by digit.\r\n j = ((xlty = xc.length < yc.length) ? xc : yc).length;\r\n\r\n for (a = b = 0; b < j; b++) {\r\n if (xc[b] != yc[b]) {\r\n xlty = xc[b] < yc[b];\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // x < y? Point xc to the array of the bigger number.\r\n if (xlty) {\r\n t = xc;\r\n xc = yc;\r\n yc = t;\r\n y.s = -y.s;\r\n }\r\n\r\n /*\r\n * Append zeros to xc if shorter. No need to add zeros to yc if shorter as subtraction only\r\n * needs to start at yc.length.\r\n */\r\n if ((b = (j = yc.length) - (i = xc.length)) > 0) for (; b--;) xc[i++] = 0;\r\n\r\n // Subtract yc from xc.\r\n for (b = i; j > a;) {\r\n if (xc[--j] < yc[j]) {\r\n for (i = j; i && !xc[--i];) xc[i] = 9;\r\n --xc[i];\r\n xc[j] += 10;\r\n }\r\n\r\n xc[j] -= yc[j];\r\n }\r\n\r\n // Remove trailing zeros.\r\n for (; xc[--b] === 0;) xc.pop();\r\n\r\n // Remove leading zeros and adjust exponent accordingly.\r\n for (; xc[0] === 0;) {\r\n xc.shift();\r\n --ye;\r\n }\r\n\r\n if (!xc[0]) {\r\n\r\n // n - n = +0\r\n y.s = 1;\r\n\r\n // Result must be zero.\r\n xc = [ye = 0];\r\n }\r\n\r\n y.c = xc;\r\n y.e = ye;\r\n\r\n return y;\r\n};\r\n\r\n\r\n/*\r\n * Return a new Big whose value is the value of this Big modulo the value of Big y.\r\n */\r\nP.mod = function (y) {\r\n var ygtx,\r\n x = this,\r\n Big = x.constructor,\r\n a = x.s,\r\n b = (y = new Big(y)).s;\r\n\r\n if (!y.c[0]) {\r\n throw Error(DIV_BY_ZERO);\r\n }\r\n\r\n x.s = y.s = 1;\r\n ygtx = y.cmp(x) == 1;\r\n x.s = a;\r\n y.s = b;\r\n\r\n if (ygtx) return new Big(x);\r\n\r\n a = Big.DP;\r\n b = Big.RM;\r\n Big.DP = Big.RM = 0;\r\n x = x.div(y);\r\n Big.DP = a;\r\n Big.RM = b;\r\n\r\n return this.minus(x.times(y));\r\n};\r\n\r\n\r\n/*\r\n * Return a new Big whose value is the value of this Big negated.\r\n */\r\nP.neg = function () {\r\n var x = new this.constructor(this);\r\n x.s = -x.s;\r\n return x;\r\n};\r\n\r\n\r\n/*\r\n * Return a new Big whose value is the value of this Big plus the value of Big y.\r\n */\r\nP.plus = P.add = function (y) {\r\n var e, k, t,\r\n x = this,\r\n Big = x.constructor;\r\n\r\n y = new Big(y);\r\n\r\n // Signs differ?\r\n if (x.s != y.s) {\r\n y.s = -y.s;\r\n return x.minus(y);\r\n }\r\n\r\n var xe = x.e,\r\n xc = x.c,\r\n ye = y.e,\r\n yc = y.c;\r\n\r\n // Either zero?\r\n if (!xc[0] || !yc[0]) {\r\n if (!yc[0]) {\r\n if (xc[0]) {\r\n y = new Big(x);\r\n } else {\r\n y.s = x.s;\r\n }\r\n }\r\n return y;\r\n }\r\n\r\n xc = xc.slice();\r\n\r\n // Prepend zeros to equalise exponents.\r\n // Note: reverse faster than unshifts.\r\n if (e = xe - ye) {\r\n if (e > 0) {\r\n ye = xe;\r\n t = yc;\r\n } else {\r\n e = -e;\r\n t = xc;\r\n }\r\n\r\n t.reverse();\r\n for (; e--;) t.push(0);\r\n t.reverse();\r\n }\r\n\r\n // Point xc to the longer array.\r\n if (xc.length - yc.length < 0) {\r\n t = yc;\r\n yc = xc;\r\n xc = t;\r\n }\r\n\r\n e = yc.length;\r\n\r\n // Only start adding at yc.length - 1 as the further digits of xc can be left as they are.\r\n for (k = 0; e; xc[e] %= 10) k = (xc[--e] = xc[e] + yc[e] + k) / 10 | 0;\r\n\r\n // No need to check for zero, as +x + +y != 0 && -x + -y != 0\r\n\r\n if (k) {\r\n xc.unshift(k);\r\n ++ye;\r\n }\r\n\r\n // Remove trailing zeros.\r\n for (e = xc.length; xc[--e] === 0;) xc.pop();\r\n\r\n y.c = xc;\r\n y.e = ye;\r\n\r\n return y;\r\n};\r\n\r\n\r\n/*\r\n * Return a Big whose value is the value of this Big raised to the power n.\r\n * If n is negative, round to a maximum of Big.DP decimal places using rounding\r\n * mode Big.RM.\r\n *\r\n * n {number} Integer, -MAX_POWER to MAX_POWER inclusive.\r\n */\r\nP.pow = function (n) {\r\n var x = this,\r\n one = new x.constructor('1'),\r\n y = one,\r\n isneg = n < 0;\r\n\r\n if (n !== ~~n || n < -MAX_POWER || n > MAX_POWER) {\r\n throw Error(INVALID + 'exponent');\r\n }\r\n\r\n if (isneg) n = -n;\r\n\r\n for (;;) {\r\n if (n & 1) y = y.times(x);\r\n n >>= 1;\r\n if (!n) break;\r\n x = x.times(x);\r\n }\r\n\r\n return isneg ? one.div(y) : y;\r\n};\r\n\r\n\r\n/*\r\n * Return a new Big whose value is the value of this Big rounded to a maximum precision of sd\r\n * significant digits using rounding mode rm, or Big.RM if rm is not specified.\r\n *\r\n * sd {number} Significant digits: integer, 1 to MAX_DP inclusive.\r\n * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up).\r\n */\r\nP.prec = function (sd, rm) {\r\n if (sd !== ~~sd || sd < 1 || sd > MAX_DP) {\r\n throw Error(INVALID + 'precision');\r\n }\r\n return round(new this.constructor(this), sd, rm);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Big whose value is the value of this Big rounded to a maximum of dp decimal places\r\n * using rounding mode rm, or Big.RM if rm is not specified.\r\n * If dp is negative, round to an integer which is a multiple of 10**-dp.\r\n * If dp is not specified, round to 0 decimal places.\r\n *\r\n * dp? {number} Integer, -MAX_DP to MAX_DP inclusive.\r\n * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up).\r\n */\r\nP.round = function (dp, rm) {\r\n if (dp === UNDEFINED) dp = 0;\r\n else if (dp !== ~~dp || dp < -MAX_DP || dp > MAX_DP) {\r\n throw Error(INVALID_DP);\r\n }\r\n return round(new this.constructor(this), dp + this.e + 1, rm);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Big whose value is the square root of the value of this Big, rounded, if\r\n * necessary, to a maximum of Big.DP decimal places using rounding mode Big.RM.\r\n */\r\nP.sqrt = function () {\r\n var r, c, t,\r\n x = this,\r\n Big = x.constructor,\r\n s = x.s,\r\n e = x.e,\r\n half = new Big('0.5');\r\n\r\n // Zero?\r\n if (!x.c[0]) return new Big(x);\r\n\r\n // Negative?\r\n if (s < 0) {\r\n throw Error(NAME + 'No square root');\r\n }\r\n\r\n // Estimate.\r\n s = Math.sqrt(+stringify(x, true, true));\r\n\r\n // Math.sqrt underflow/overflow?\r\n // Re-estimate: pass x coefficient to Math.sqrt as integer, then adjust the result exponent.\r\n if (s === 0 || s === 1 / 0) {\r\n c = x.c.join('');\r\n if (!(c.length + e & 1)) c += '0';\r\n s = Math.sqrt(c);\r\n e = ((e + 1) / 2 | 0) - (e < 0 || e & 1);\r\n r = new Big((s == 1 / 0 ? '5e' : (s = s.toExponential()).slice(0, s.indexOf('e') + 1)) + e);\r\n } else {\r\n r = new Big(s + '');\r\n }\r\n\r\n e = r.e + (Big.DP += 4);\r\n\r\n // Newton-Raphson iteration.\r\n do {\r\n t = r;\r\n r = half.times(t.plus(x.div(t)));\r\n } while (t.c.slice(0, e).join('') !== r.c.slice(0, e).join(''));\r\n\r\n return round(r, (Big.DP -= 4) + r.e + 1, Big.RM);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Big whose value is the value of this Big times the value of Big y.\r\n */\r\nP.times = P.mul = function (y) {\r\n var c,\r\n x = this,\r\n Big = x.constructor,\r\n xc = x.c,\r\n yc = (y = new Big(y)).c,\r\n a = xc.length,\r\n b = yc.length,\r\n i = x.e,\r\n j = y.e;\r\n\r\n // Determine sign of result.\r\n y.s = x.s == y.s ? 1 : -1;\r\n\r\n // Return signed 0 if either 0.\r\n if (!xc[0] || !yc[0]) {\r\n y.c = [y.e = 0];\r\n return y;\r\n }\r\n\r\n // Initialise exponent of result as x.e + y.e.\r\n y.e = i + j;\r\n\r\n // If array xc has fewer digits than yc, swap xc and yc, and lengths.\r\n if (a < b) {\r\n c = xc;\r\n xc = yc;\r\n yc = c;\r\n j = a;\r\n a = b;\r\n b = j;\r\n }\r\n\r\n // Initialise coefficient array of result with zeros.\r\n for (c = new Array(j = a + b); j--;) c[j] = 0;\r\n\r\n // Multiply.\r\n\r\n // i is initially xc.length.\r\n for (i = b; i--;) {\r\n b = 0;\r\n\r\n // a is yc.length.\r\n for (j = a + i; j > i;) {\r\n\r\n // Current sum of products at this digit position, plus carry.\r\n b = c[j] + yc[i] * xc[j - i - 1] + b;\r\n c[j--] = b % 10;\r\n\r\n // carry\r\n b = b / 10 | 0;\r\n }\r\n\r\n c[j] = b;\r\n }\r\n\r\n // Increment result exponent if there is a final carry, otherwise remove leading zero.\r\n if (b) ++y.e;\r\n else c.shift();\r\n\r\n // Remove trailing zeros.\r\n for (i = c.length; !c[--i];) c.pop();\r\n y.c = c;\r\n\r\n return y;\r\n};\r\n\r\n\r\n/*\r\n * Return a string representing the value of this Big in exponential notation rounded to dp fixed\r\n * decimal places using rounding mode rm, or Big.RM if rm is not specified.\r\n *\r\n * dp? {number} Decimal places: integer, 0 to MAX_DP inclusive.\r\n * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up).\r\n */\r\nP.toExponential = function (dp, rm) {\r\n var x = this,\r\n n = x.c[0];\r\n\r\n if (dp !== UNDEFINED) {\r\n if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {\r\n throw Error(INVALID_DP);\r\n }\r\n x = round(new x.constructor(x), ++dp, rm);\r\n for (; x.c.length < dp;) x.c.push(0);\r\n }\r\n\r\n return stringify(x, true, !!n);\r\n};\r\n\r\n\r\n/*\r\n * Return a string representing the value of this Big in normal notation rounded to dp fixed\r\n * decimal places using rounding mode rm, or Big.RM if rm is not specified.\r\n *\r\n * dp? {number} Decimal places: integer, 0 to MAX_DP inclusive.\r\n * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up).\r\n *\r\n * (-0).toFixed(0) is '0', but (-0.1).toFixed(0) is '-0'.\r\n * (-0).toFixed(1) is '0.0', but (-0.01).toFixed(1) is '-0.0'.\r\n */\r\nP.toFixed = function (dp, rm) {\r\n var x = this,\r\n n = x.c[0];\r\n\r\n if (dp !== UNDEFINED) {\r\n if (dp !== ~~dp || dp < 0 || dp > MAX_DP) {\r\n throw Error(INVALID_DP);\r\n }\r\n x = round(new x.constructor(x), dp + x.e + 1, rm);\r\n\r\n // x.e may have changed if the value is rounded up.\r\n for (dp = dp + x.e + 1; x.c.length < dp;) x.c.push(0);\r\n }\r\n\r\n return stringify(x, false, !!n);\r\n};\r\n\r\n\r\n/*\r\n * Return a string representing the value of this Big.\r\n * Return exponential notation if this Big has a positive exponent equal to or greater than\r\n * Big.PE, or a negative exponent equal to or less than Big.NE.\r\n * Omit the sign for negative zero.\r\n */\r\nP[Symbol.for('nodejs.util.inspect.custom')] = P.toJSON = P.toString = function () {\r\n var x = this,\r\n Big = x.constructor;\r\n return stringify(x, x.e <= Big.NE || x.e >= Big.PE, !!x.c[0]);\r\n};\r\n\r\n\r\n/*\r\n * Return the value of this Big as a primitve number.\r\n */\r\nP.toNumber = function () {\r\n var n = +stringify(this, true, true);\r\n if (this.constructor.strict === true && !this.eq(n.toString())) {\r\n throw Error(NAME + 'Imprecise conversion');\r\n }\r\n return n;\r\n};\r\n\r\n\r\n/*\r\n * Return a string representing the value of this Big rounded to sd significant digits using\r\n * rounding mode rm, or Big.RM if rm is not specified.\r\n * Use exponential notation if sd is less than the number of digits necessary to represent\r\n * the integer part of the value in normal notation.\r\n *\r\n * sd {number} Significant digits: integer, 1 to MAX_DP inclusive.\r\n * rm? {number} Rounding mode: 0 (down), 1 (half-up), 2 (half-even) or 3 (up).\r\n */\r\nP.toPrecision = function (sd, rm) {\r\n var x = this,\r\n Big = x.constructor,\r\n n = x.c[0];\r\n\r\n if (sd !== UNDEFINED) {\r\n if (sd !== ~~sd || sd < 1 || sd > MAX_DP) {\r\n throw Error(INVALID + 'precision');\r\n }\r\n x = round(new Big(x), sd, rm);\r\n for (; x.c.length < sd;) x.c.push(0);\r\n }\r\n\r\n return stringify(x, sd <= x.e || x.e <= Big.NE || x.e >= Big.PE, !!n);\r\n};\r\n\r\n\r\n/*\r\n * Return a string representing the value of this Big.\r\n * Return exponential notation if this Big has a positive exponent equal to or greater than\r\n * Big.PE, or a negative exponent equal to or less than Big.NE.\r\n * Include the sign for negative zero.\r\n */\r\nP.valueOf = function () {\r\n var x = this,\r\n Big = x.constructor;\r\n if (Big.strict === true) {\r\n throw Error(NAME + 'valueOf disallowed');\r\n }\r\n return stringify(x, x.e <= Big.NE || x.e >= Big.PE, true);\r\n};\r\n\r\n\r\n// Export\r\n\r\n\r\nexport var Big = _Big_();\r\n\r\n/// \r\nexport default Big;\r\n","export * from \"./crypto.js\";\nexport * from \"./transaction.js\";\nexport * from \"./misc.js\";\nexport * from \"./storage.js\";\n\nimport { serialize, deserialize } from \"borsh\";\nimport * as borshSchema from \"@fastnear/borsh-schema\";\n\n// exports (or re-exports as well)\nconst exp = {\n borsh: {\n serialize,\n deserialize\n },\n borshSchema,\n}\n\nexport { exp }\n","/**\n * Internal assertion helpers.\n * @module\n */\n\n/** Asserts something is positive integer. */\nfunction anumber(n: number): void {\n if (!Number.isSafeInteger(n) || n < 0) throw new Error('positive integer expected, got ' + n);\n}\n\n/** Is number an Uint8Array? Copied from utils for perf. */\nfunction isBytes(a: unknown): a is Uint8Array {\n return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\n}\n\n/** Asserts something is Uint8Array. */\nfunction abytes(b: Uint8Array | undefined, ...lengths: number[]): void {\n if (!isBytes(b)) throw new Error('Uint8Array expected');\n if (lengths.length > 0 && !lengths.includes(b.length))\n throw new Error('Uint8Array expected of length ' + lengths + ', got length=' + b.length);\n}\n\n/** Hash interface. */\nexport type Hash = {\n (data: Uint8Array): Uint8Array;\n blockLen: number;\n outputLen: number;\n create: any;\n};\n\n/** Asserts something is hash */\nfunction ahash(h: Hash): void {\n if (typeof h !== 'function' || typeof h.create !== 'function')\n throw new Error('Hash should be wrapped by utils.wrapConstructor');\n anumber(h.outputLen);\n anumber(h.blockLen);\n}\n\n/** Asserts a hash instance has not been destroyed / finished */\nfunction aexists(instance: any, checkFinished = true): void {\n if (instance.destroyed) throw new Error('Hash instance has been destroyed');\n if (checkFinished && instance.finished) throw new Error('Hash#digest() has already been called');\n}\n\n/** Asserts output is properly-sized byte array */\nfunction aoutput(out: any, instance: any): void {\n abytes(out);\n const min = instance.outputLen;\n if (out.length < min) {\n throw new Error('digestInto() expects output buffer of length at least ' + min);\n }\n}\n\nexport { anumber, abytes, ahash, aexists, aoutput };\n","/**\n * Internal webcrypto alias.\n * We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.\n * See utils.ts for details.\n * @module\n */\ndeclare const globalThis: Record | undefined;\nexport const crypto: any =\n typeof globalThis === 'object' && 'crypto' in globalThis ? globalThis.crypto : undefined;\n","/**\n * Utilities for hex, bytes, CSPRNG.\n * @module\n */\n/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */\n\n// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.\n// node.js versions earlier than v19 don't declare it in global scope.\n// For node.js, package.json#exports field mapping rewrites import\n// from `crypto` to `cryptoNode`, which imports native module.\n// Makes the utils un-importable in browsers without a bundler.\n// Once node.js 18 is deprecated (2025-04-30), we can just drop the import.\nimport { crypto } from '@noble/hashes/crypto';\nimport { abytes } from './_assert.js';\n// export { isBytes } from './_assert.js';\n// We can't reuse isBytes from _assert, because somehow this causes huge perf issues\nexport function isBytes(a: unknown): a is Uint8Array {\n return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\n}\n\n// prettier-ignore\nexport type TypedArray = Int8Array | Uint8ClampedArray | Uint8Array |\n Uint16Array | Int16Array | Uint32Array | Int32Array;\n\n// Cast array to different type\nexport function u8(arr: TypedArray): Uint8Array {\n return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);\n}\nexport function u32(arr: TypedArray): Uint32Array {\n return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));\n}\n\n// Cast array to view\nexport function createView(arr: TypedArray): DataView {\n return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/** The rotate right (circular right shift) operation for uint32 */\nexport function rotr(word: number, shift: number): number {\n return (word << (32 - shift)) | (word >>> shift);\n}\n/** The rotate left (circular left shift) operation for uint32 */\nexport function rotl(word: number, shift: number): number {\n return (word << shift) | ((word >>> (32 - shift)) >>> 0);\n}\n\n/** Is current platform little-endian? Most are. Big-Endian platform: IBM */\nexport const isLE: boolean = /* @__PURE__ */ (() =>\n new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)();\n// The byte swap operation for uint32\nexport function byteSwap(word: number): number {\n return (\n ((word << 24) & 0xff000000) |\n ((word << 8) & 0xff0000) |\n ((word >>> 8) & 0xff00) |\n ((word >>> 24) & 0xff)\n );\n}\n/** Conditionally byte swap if on a big-endian platform */\nexport const byteSwapIfBE: (n: number) => number = isLE\n ? (n: number) => n\n : (n: number) => byteSwap(n);\n\n/** In place byte swap for Uint32Array */\nexport function byteSwap32(arr: Uint32Array): void {\n for (let i = 0; i < arr.length; i++) {\n arr[i] = byteSwap(arr[i]);\n }\n}\n\n// Array where index 0xf0 (240) is mapped to string 'f0'\nconst hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>\n i.toString(16).padStart(2, '0')\n);\n/**\n * Convert byte array to hex string.\n * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n abytes(bytes);\n // pre-caching improves the speed 6x\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n hex += hexes[bytes[i]];\n }\n return hex;\n}\n\n// We use optimized technique to convert hex string to byte array\nconst asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 } as const;\nfunction asciiToBase16(ch: number): number | undefined {\n if (ch >= asciis._0 && ch <= asciis._9) return ch - asciis._0; // '2' => 50-48\n if (ch >= asciis.A && ch <= asciis.F) return ch - (asciis.A - 10); // 'B' => 66-(65-10)\n if (ch >= asciis.a && ch <= asciis.f) return ch - (asciis.a - 10); // 'b' => 98-(97-10)\n return;\n}\n\n/**\n * Convert hex string to byte array.\n * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])\n */\nexport function hexToBytes(hex: string): Uint8Array {\n if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);\n const hl = hex.length;\n const al = hl / 2;\n if (hl % 2) throw new Error('hex string expected, got unpadded hex of length ' + hl);\n const array = new Uint8Array(al);\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\n const n1 = asciiToBase16(hex.charCodeAt(hi));\n const n2 = asciiToBase16(hex.charCodeAt(hi + 1));\n if (n1 === undefined || n2 === undefined) {\n const char = hex[hi] + hex[hi + 1];\n throw new Error('hex string expected, got non-hex character \"' + char + '\" at index ' + hi);\n }\n array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163\n }\n return array;\n}\n\n/**\n * There is no setImmediate in browser and setTimeout is slow.\n * Call of async fn will return Promise, which will be fullfiled only on\n * next scheduler queue processing step and this is exactly what we need.\n */\nexport const nextTick = async (): Promise => {};\n\n/** Returns control to thread each 'tick' ms to avoid blocking. */\nexport async function asyncLoop(\n iters: number,\n tick: number,\n cb: (i: number) => void\n): Promise {\n let ts = Date.now();\n for (let i = 0; i < iters; i++) {\n cb(i);\n // Date.now() is not monotonic, so in case if clock goes backwards we return return control too\n const diff = Date.now() - ts;\n if (diff >= 0 && diff < tick) continue;\n await nextTick();\n ts += diff;\n }\n}\n\n// Global symbols in both browsers and Node.js since v11\n// See https://github.com/microsoft/TypeScript/issues/31535\ndeclare const TextEncoder: any;\n\n/**\n * Convert JS string to byte array.\n * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])\n */\nexport function utf8ToBytes(str: string): Uint8Array {\n if (typeof str !== 'string') throw new Error('utf8ToBytes expected string, got ' + typeof str);\n return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809\n}\n\n/** Accepted input of hash functions. Strings are converted to byte arrays. */\nexport type Input = Uint8Array | string;\n/**\n * Normalizes (non-hex) string or Uint8Array to Uint8Array.\n * Warning: when Uint8Array is passed, it would NOT get copied.\n * Keep in mind for future mutable operations.\n */\nexport function toBytes(data: Input): Uint8Array {\n if (typeof data === 'string') data = utf8ToBytes(data);\n abytes(data);\n return data;\n}\n\n/**\n * Copies several Uint8Arrays into one.\n */\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\n let sum = 0;\n for (let i = 0; i < arrays.length; i++) {\n const a = arrays[i];\n abytes(a);\n sum += a.length;\n }\n const res = new Uint8Array(sum);\n for (let i = 0, pad = 0; i < arrays.length; i++) {\n const a = arrays[i];\n res.set(a, pad);\n pad += a.length;\n }\n return res;\n}\n\n/** For runtime check if class implements interface */\nexport abstract class Hash> {\n abstract blockLen: number; // Bytes per block\n abstract outputLen: number; // Bytes in output\n abstract update(buf: Input): this;\n // Writes digest into buf\n abstract digestInto(buf: Uint8Array): void;\n abstract digest(): Uint8Array;\n /**\n * Resets internal state. Makes Hash instance unusable.\n * Reset is impossible for keyed hashes if key is consumed into state. If digest is not consumed\n * by user, they will need to manually call `destroy()` when zeroing is necessary.\n */\n abstract destroy(): void;\n /**\n * Clones hash instance. Unsafe: doesn't check whether `to` is valid. Can be used as `clone()`\n * when no options are passed.\n * Reasons to use `_cloneInto` instead of clone: 1) performance 2) reuse instance => all internal\n * buffers are overwritten => causes buffer overwrite which is used for digest in some cases.\n * There are no guarantees for clean-up because it's impossible in JS.\n */\n abstract _cloneInto(to?: T): T;\n // Safe version that clones internal state\n clone(): T {\n return this._cloneInto();\n }\n}\n\n/**\n * XOF: streaming API to read digest in chunks.\n * Same as 'squeeze' in keccak/k12 and 'seek' in blake3, but more generic name.\n * When hash used in XOF mode it is up to user to call '.destroy' afterwards, since we cannot\n * destroy state, next call can require more bytes.\n */\nexport type HashXOF> = Hash & {\n xof(bytes: number): Uint8Array; // Read 'bytes' bytes from digest stream\n xofInto(buf: Uint8Array): Uint8Array; // read buf.length bytes from digest stream into buf\n};\n\ntype EmptyObj = {};\nexport function checkOpts(\n defaults: T1,\n opts?: T2\n): T1 & T2 {\n if (opts !== undefined && {}.toString.call(opts) !== '[object Object]')\n throw new Error('Options should be object or undefined');\n const merged = Object.assign(defaults, opts);\n return merged as T1 & T2;\n}\n\n/** Hash function */\nexport type CHash = ReturnType;\n/** Hash function with output */\nexport type CHashO = ReturnType;\n/** XOF with output */\nexport type CHashXO = ReturnType;\n\n/** Wraps hash function, creating an interface on top of it */\nexport function wrapConstructor>(\n hashCons: () => Hash\n): {\n (msg: Input): Uint8Array;\n outputLen: number;\n blockLen: number;\n create(): Hash;\n} {\n const hashC = (msg: Input): Uint8Array => hashCons().update(toBytes(msg)).digest();\n const tmp = hashCons();\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = () => hashCons();\n return hashC;\n}\n\nexport function wrapConstructorWithOpts, T extends Object>(\n hashCons: (opts?: T) => Hash\n): {\n (msg: Input, opts?: T): Uint8Array;\n outputLen: number;\n blockLen: number;\n create(opts: T): Hash;\n} {\n const hashC = (msg: Input, opts?: T): Uint8Array => hashCons(opts).update(toBytes(msg)).digest();\n const tmp = hashCons({} as T);\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = (opts: T) => hashCons(opts);\n return hashC;\n}\n\nexport function wrapXOFConstructorWithOpts, T extends Object>(\n hashCons: (opts?: T) => HashXOF\n): {\n (msg: Input, opts?: T): Uint8Array;\n outputLen: number;\n blockLen: number;\n create(opts: T): HashXOF;\n} {\n const hashC = (msg: Input, opts?: T): Uint8Array => hashCons(opts).update(toBytes(msg)).digest();\n const tmp = hashCons({} as T);\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = (opts: T) => hashCons(opts);\n return hashC;\n}\n\n/** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */\nexport function randomBytes(bytesLength = 32): Uint8Array {\n if (crypto && typeof crypto.getRandomValues === 'function') {\n return crypto.getRandomValues(new Uint8Array(bytesLength));\n }\n // Legacy Node.js compatibility\n if (crypto && typeof crypto.randomBytes === 'function') {\n return crypto.randomBytes(bytesLength);\n }\n throw new Error('crypto.getRandomValues must be defined');\n}\n","/**\n * Internal Merkle-Damgard hash utils.\n * @module\n */\nimport { aexists, aoutput } from './_assert.js';\nimport { type Input, Hash, createView, toBytes } from './utils.js';\n\n/** Polyfill for Safari 14. https://caniuse.com/mdn-javascript_builtins_dataview_setbiguint64 */\nexport function setBigUint64(\n view: DataView,\n byteOffset: number,\n value: bigint,\n isLE: boolean\n): void {\n if (typeof view.setBigUint64 === 'function') return view.setBigUint64(byteOffset, value, isLE);\n const _32n = BigInt(32);\n const _u32_max = BigInt(0xffffffff);\n const wh = Number((value >> _32n) & _u32_max);\n const wl = Number(value & _u32_max);\n const h = isLE ? 4 : 0;\n const l = isLE ? 0 : 4;\n view.setUint32(byteOffset + h, wh, isLE);\n view.setUint32(byteOffset + l, wl, isLE);\n}\n\n/** Choice: a ? b : c */\nexport function Chi(a: number, b: number, c: number): number {\n return (a & b) ^ (~a & c);\n}\n\n/** Majority function, true if any two inputs is true. */\nexport function Maj(a: number, b: number, c: number): number {\n return (a & b) ^ (a & c) ^ (b & c);\n}\n\n/**\n * Merkle-Damgard hash construction base class.\n * Could be used to create MD5, RIPEMD, SHA1, SHA2.\n */\nexport abstract class HashMD> extends Hash {\n protected abstract process(buf: DataView, offset: number): void;\n protected abstract get(): number[];\n protected abstract set(...args: number[]): void;\n abstract destroy(): void;\n protected abstract roundClean(): void;\n // For partial updates less than block size\n protected buffer: Uint8Array;\n protected view: DataView;\n protected finished = false;\n protected length = 0;\n protected pos = 0;\n protected destroyed = false;\n\n constructor(\n readonly blockLen: number,\n public outputLen: number,\n readonly padOffset: number,\n readonly isLE: boolean\n ) {\n super();\n this.buffer = new Uint8Array(blockLen);\n this.view = createView(this.buffer);\n }\n update(data: Input): this {\n aexists(this);\n const { view, buffer, blockLen } = this;\n data = toBytes(data);\n const len = data.length;\n for (let pos = 0; pos < len; ) {\n const take = Math.min(blockLen - this.pos, len - pos);\n // Fast path: we have at least one block in input, cast it to view and process\n if (take === blockLen) {\n const dataView = createView(data);\n for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos);\n continue;\n }\n buffer.set(data.subarray(pos, pos + take), this.pos);\n this.pos += take;\n pos += take;\n if (this.pos === blockLen) {\n this.process(view, 0);\n this.pos = 0;\n }\n }\n this.length += data.length;\n this.roundClean();\n return this;\n }\n digestInto(out: Uint8Array): void {\n aexists(this);\n aoutput(out, this);\n this.finished = true;\n // Padding\n // We can avoid allocation of buffer for padding completely if it\n // was previously not allocated here. But it won't change performance.\n const { buffer, view, blockLen, isLE } = this;\n let { pos } = this;\n // append the bit '1' to the message\n buffer[pos++] = 0b10000000;\n this.buffer.subarray(pos).fill(0);\n // we have less than padOffset left in buffer, so we cannot put length in\n // current block, need process it and pad again\n if (this.padOffset > blockLen - pos) {\n this.process(view, 0);\n pos = 0;\n }\n // Pad until full block byte with zeros\n for (let i = pos; i < blockLen; i++) buffer[i] = 0;\n // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that\n // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.\n // So we just write lowest 64 bits of that value.\n setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);\n this.process(view, 0);\n const oview = createView(out);\n const len = this.outputLen;\n // NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT\n if (len % 4) throw new Error('_sha2: outputLen should be aligned to 32bit');\n const outLen = len / 4;\n const state = this.get();\n if (outLen > state.length) throw new Error('_sha2: outputLen bigger than state');\n for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE);\n }\n digest(): Uint8Array {\n const { buffer, outputLen } = this;\n this.digestInto(buffer);\n const res = buffer.slice(0, outputLen);\n this.destroy();\n return res;\n }\n _cloneInto(to?: T): T {\n to ||= new (this.constructor as any)() as T;\n to.set(...this.get());\n const { blockLen, buffer, length, finished, destroyed, pos } = this;\n to.length = length;\n to.pos = pos;\n to.finished = finished;\n to.destroyed = destroyed;\n if (length % blockLen) to.buffer.set(buffer);\n return to;\n }\n}\n","/**\n * Internal helpers for u64. BigUint64Array is too slow as per 2025, so we implement it using Uint32Array.\n * @todo re-check https://issues.chromium.org/issues/42212588\n * @module\n */\nconst U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);\nconst _32n = /* @__PURE__ */ BigInt(32);\n\nfunction fromBig(\n n: bigint,\n le = false\n): {\n h: number;\n l: number;\n} {\n if (le) return { h: Number(n & U32_MASK64), l: Number((n >> _32n) & U32_MASK64) };\n return { h: Number((n >> _32n) & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };\n}\n\nfunction split(lst: bigint[], le = false): Uint32Array[] {\n let Ah = new Uint32Array(lst.length);\n let Al = new Uint32Array(lst.length);\n for (let i = 0; i < lst.length; i++) {\n const { h, l } = fromBig(lst[i], le);\n [Ah[i], Al[i]] = [h, l];\n }\n return [Ah, Al];\n}\n\nconst toBig = (h: number, l: number): bigint => (BigInt(h >>> 0) << _32n) | BigInt(l >>> 0);\n// for Shift in [0, 32)\nconst shrSH = (h: number, _l: number, s: number): number => h >>> s;\nconst shrSL = (h: number, l: number, s: number): number => (h << (32 - s)) | (l >>> s);\n// Right rotate for Shift in [1, 32)\nconst rotrSH = (h: number, l: number, s: number): number => (h >>> s) | (l << (32 - s));\nconst rotrSL = (h: number, l: number, s: number): number => (h << (32 - s)) | (l >>> s);\n// Right rotate for Shift in (32, 64), NOTE: 32 is special case.\nconst rotrBH = (h: number, l: number, s: number): number => (h << (64 - s)) | (l >>> (s - 32));\nconst rotrBL = (h: number, l: number, s: number): number => (h >>> (s - 32)) | (l << (64 - s));\n// Right rotate for shift===32 (just swaps l&h)\nconst rotr32H = (_h: number, l: number): number => l;\nconst rotr32L = (h: number, _l: number): number => h;\n// Left rotate for Shift in [1, 32)\nconst rotlSH = (h: number, l: number, s: number): number => (h << s) | (l >>> (32 - s));\nconst rotlSL = (h: number, l: number, s: number): number => (l << s) | (h >>> (32 - s));\n// Left rotate for Shift in (32, 64), NOTE: 32 is special case.\nconst rotlBH = (h: number, l: number, s: number): number => (l << (s - 32)) | (h >>> (64 - s));\nconst rotlBL = (h: number, l: number, s: number): number => (h << (s - 32)) | (l >>> (64 - s));\n\n// JS uses 32-bit signed integers for bitwise operations which means we cannot\n// simple take carry out of low bit sum by shift, we need to use division.\nfunction add(\n Ah: number,\n Al: number,\n Bh: number,\n Bl: number\n): {\n h: number;\n l: number;\n} {\n const l = (Al >>> 0) + (Bl >>> 0);\n return { h: (Ah + Bh + ((l / 2 ** 32) | 0)) | 0, l: l | 0 };\n}\n// Addition with more than 2 elements\nconst add3L = (Al: number, Bl: number, Cl: number): number => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);\nconst add3H = (low: number, Ah: number, Bh: number, Ch: number): number =>\n (Ah + Bh + Ch + ((low / 2 ** 32) | 0)) | 0;\nconst add4L = (Al: number, Bl: number, Cl: number, Dl: number): number =>\n (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);\nconst add4H = (low: number, Ah: number, Bh: number, Ch: number, Dh: number): number =>\n (Ah + Bh + Ch + Dh + ((low / 2 ** 32) | 0)) | 0;\nconst add5L = (Al: number, Bl: number, Cl: number, Dl: number, El: number): number =>\n (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);\nconst add5H = (low: number, Ah: number, Bh: number, Ch: number, Dh: number, Eh: number): number =>\n (Ah + Bh + Ch + Dh + Eh + ((low / 2 ** 32) | 0)) | 0;\n\n// prettier-ignore\nexport {\n fromBig, split, toBig,\n shrSH, shrSL,\n rotrSH, rotrSL, rotrBH, rotrBL,\n rotr32H, rotr32L,\n rotlSH, rotlSL, rotlBH, rotlBL,\n add, add3L, add3H, add4L, add4H, add5H, add5L,\n};\n// prettier-ignore\nconst u64: { fromBig: typeof fromBig; split: typeof split; toBig: (h: number, l: number) => bigint; shrSH: (h: number, _l: number, s: number) => number; shrSL: (h: number, l: number, s: number) => number; rotrSH: (h: number, l: number, s: number) => number; rotrSL: (h: number, l: number, s: number) => number; rotrBH: (h: number, l: number, s: number) => number; rotrBL: (h: number, l: number, s: number) => number; rotr32H: (_h: number, l: number) => number; rotr32L: (h: number, _l: number) => number; rotlSH: (h: number, l: number, s: number) => number; rotlSL: (h: number, l: number, s: number) => number; rotlBH: (h: number, l: number, s: number) => number; rotlBL: (h: number, l: number, s: number) => number; add: typeof add; add3L: (Al: number, Bl: number, Cl: number) => number; add3H: (low: number, Ah: number, Bh: number, Ch: number) => number; add4L: (Al: number, Bl: number, Cl: number, Dl: number) => number; add4H: (low: number, Ah: number, Bh: number, Ch: number, Dh: number) => number; add5H: (low: number, Ah: number, Bh: number, Ch: number, Dh: number, Eh: number) => number; add5L: (Al: number, Bl: number, Cl: number, Dl: number, El: number) => number; } = {\n fromBig, split, toBig,\n shrSH, shrSL,\n rotrSH, rotrSL, rotrBH, rotrBL,\n rotr32H, rotr32L,\n rotlSH, rotlSL, rotlBH, rotlBL,\n add, add3L, add3H, add4L, add4H, add5H, add5L,\n};\nexport default u64;\n","/**\n * SHA2-512 a.k.a. sha512 and sha384. It is slower than sha256 in js because u64 operations are slow.\n *\n * Check out [RFC 4634](https://datatracker.ietf.org/doc/html/rfc4634) and\n * [the paper on truncated SHA512/256](https://eprint.iacr.org/2010/548.pdf).\n * @module\n */\nimport { HashMD } from './_md.js';\nimport u64 from './_u64.js';\nimport { type CHash, wrapConstructor } from './utils.js';\n\n// Round contants (first 32 bits of the fractional parts of the cube roots of the first 80 primes 2..409):\n// prettier-ignore\nconst [SHA512_Kh, SHA512_Kl] = /* @__PURE__ */ (() => u64.split([\n '0x428a2f98d728ae22', '0x7137449123ef65cd', '0xb5c0fbcfec4d3b2f', '0xe9b5dba58189dbbc',\n '0x3956c25bf348b538', '0x59f111f1b605d019', '0x923f82a4af194f9b', '0xab1c5ed5da6d8118',\n '0xd807aa98a3030242', '0x12835b0145706fbe', '0x243185be4ee4b28c', '0x550c7dc3d5ffb4e2',\n '0x72be5d74f27b896f', '0x80deb1fe3b1696b1', '0x9bdc06a725c71235', '0xc19bf174cf692694',\n '0xe49b69c19ef14ad2', '0xefbe4786384f25e3', '0x0fc19dc68b8cd5b5', '0x240ca1cc77ac9c65',\n '0x2de92c6f592b0275', '0x4a7484aa6ea6e483', '0x5cb0a9dcbd41fbd4', '0x76f988da831153b5',\n '0x983e5152ee66dfab', '0xa831c66d2db43210', '0xb00327c898fb213f', '0xbf597fc7beef0ee4',\n '0xc6e00bf33da88fc2', '0xd5a79147930aa725', '0x06ca6351e003826f', '0x142929670a0e6e70',\n '0x27b70a8546d22ffc', '0x2e1b21385c26c926', '0x4d2c6dfc5ac42aed', '0x53380d139d95b3df',\n '0x650a73548baf63de', '0x766a0abb3c77b2a8', '0x81c2c92e47edaee6', '0x92722c851482353b',\n '0xa2bfe8a14cf10364', '0xa81a664bbc423001', '0xc24b8b70d0f89791', '0xc76c51a30654be30',\n '0xd192e819d6ef5218', '0xd69906245565a910', '0xf40e35855771202a', '0x106aa07032bbd1b8',\n '0x19a4c116b8d2d0c8', '0x1e376c085141ab53', '0x2748774cdf8eeb99', '0x34b0bcb5e19b48a8',\n '0x391c0cb3c5c95a63', '0x4ed8aa4ae3418acb', '0x5b9cca4f7763e373', '0x682e6ff3d6b2b8a3',\n '0x748f82ee5defb2fc', '0x78a5636f43172f60', '0x84c87814a1f0ab72', '0x8cc702081a6439ec',\n '0x90befffa23631e28', '0xa4506cebde82bde9', '0xbef9a3f7b2c67915', '0xc67178f2e372532b',\n '0xca273eceea26619c', '0xd186b8c721c0c207', '0xeada7dd6cde0eb1e', '0xf57d4f7fee6ed178',\n '0x06f067aa72176fba', '0x0a637dc5a2c898a6', '0x113f9804bef90dae', '0x1b710b35131c471b',\n '0x28db77f523047d84', '0x32caab7b40c72493', '0x3c9ebe0a15c9bebc', '0x431d67c49c100d4c',\n '0x4cc5d4becb3e42b6', '0x597f299cfc657e2a', '0x5fcb6fab3ad6faec', '0x6c44198c4a475817'\n].map(n => BigInt(n))))();\n\n// Temporary buffer, not used to store anything between runs\nconst SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);\nconst SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);\nexport class SHA512 extends HashMD {\n // We cannot use array here since array allows indexing by variable which means optimizer/compiler cannot use registers.\n // Also looks cleaner and easier to verify with spec.\n // Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):\n // h -- high 32 bits, l -- low 32 bits\n protected Ah: number = 0x6a09e667 | 0;\n protected Al: number = 0xf3bcc908 | 0;\n protected Bh: number = 0xbb67ae85 | 0;\n protected Bl: number = 0x84caa73b | 0;\n protected Ch: number = 0x3c6ef372 | 0;\n protected Cl: number = 0xfe94f82b | 0;\n protected Dh: number = 0xa54ff53a | 0;\n protected Dl: number = 0x5f1d36f1 | 0;\n protected Eh: number = 0x510e527f | 0;\n protected El: number = 0xade682d1 | 0;\n protected Fh: number = 0x9b05688c | 0;\n protected Fl: number = 0x2b3e6c1f | 0;\n protected Gh: number = 0x1f83d9ab | 0;\n protected Gl: number = 0xfb41bd6b | 0;\n protected Hh: number = 0x5be0cd19 | 0;\n protected Hl: number = 0x137e2179 | 0;\n\n constructor() {\n super(128, 64, 16, false);\n }\n // prettier-ignore\n protected get(): [\n number, number, number, number, number, number, number, number,\n number, number, number, number, number, number, number, number\n ] {\n const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\n return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl];\n }\n // prettier-ignore\n protected set(\n Ah: number, Al: number, Bh: number, Bl: number, Ch: number, Cl: number, Dh: number, Dl: number,\n Eh: number, El: number, Fh: number, Fl: number, Gh: number, Gl: number, Hh: number, Hl: number\n ): void {\n this.Ah = Ah | 0;\n this.Al = Al | 0;\n this.Bh = Bh | 0;\n this.Bl = Bl | 0;\n this.Ch = Ch | 0;\n this.Cl = Cl | 0;\n this.Dh = Dh | 0;\n this.Dl = Dl | 0;\n this.Eh = Eh | 0;\n this.El = El | 0;\n this.Fh = Fh | 0;\n this.Fl = Fl | 0;\n this.Gh = Gh | 0;\n this.Gl = Gl | 0;\n this.Hh = Hh | 0;\n this.Hl = Hl | 0;\n }\n protected process(view: DataView, offset: number): void {\n // Extend the first 16 words into the remaining 64 words w[16..79] of the message schedule array\n for (let i = 0; i < 16; i++, offset += 4) {\n SHA512_W_H[i] = view.getUint32(offset);\n SHA512_W_L[i] = view.getUint32((offset += 4));\n }\n for (let i = 16; i < 80; i++) {\n // s0 := (w[i-15] rightrotate 1) xor (w[i-15] rightrotate 8) xor (w[i-15] rightshift 7)\n const W15h = SHA512_W_H[i - 15] | 0;\n const W15l = SHA512_W_L[i - 15] | 0;\n const s0h = u64.rotrSH(W15h, W15l, 1) ^ u64.rotrSH(W15h, W15l, 8) ^ u64.shrSH(W15h, W15l, 7);\n const s0l = u64.rotrSL(W15h, W15l, 1) ^ u64.rotrSL(W15h, W15l, 8) ^ u64.shrSL(W15h, W15l, 7);\n // s1 := (w[i-2] rightrotate 19) xor (w[i-2] rightrotate 61) xor (w[i-2] rightshift 6)\n const W2h = SHA512_W_H[i - 2] | 0;\n const W2l = SHA512_W_L[i - 2] | 0;\n const s1h = u64.rotrSH(W2h, W2l, 19) ^ u64.rotrBH(W2h, W2l, 61) ^ u64.shrSH(W2h, W2l, 6);\n const s1l = u64.rotrSL(W2h, W2l, 19) ^ u64.rotrBL(W2h, W2l, 61) ^ u64.shrSL(W2h, W2l, 6);\n // SHA256_W[i] = s0 + s1 + SHA256_W[i - 7] + SHA256_W[i - 16];\n const SUMl = u64.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]);\n const SUMh = u64.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]);\n SHA512_W_H[i] = SUMh | 0;\n SHA512_W_L[i] = SUMl | 0;\n }\n let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;\n // Compression function main loop, 80 rounds\n for (let i = 0; i < 80; i++) {\n // S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41)\n const sigma1h = u64.rotrSH(Eh, El, 14) ^ u64.rotrSH(Eh, El, 18) ^ u64.rotrBH(Eh, El, 41);\n const sigma1l = u64.rotrSL(Eh, El, 14) ^ u64.rotrSL(Eh, El, 18) ^ u64.rotrBL(Eh, El, 41);\n //const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\n const CHIh = (Eh & Fh) ^ (~Eh & Gh);\n const CHIl = (El & Fl) ^ (~El & Gl);\n // T1 = H + sigma1 + Chi(E, F, G) + SHA512_K[i] + SHA512_W[i]\n // prettier-ignore\n const T1ll = u64.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]);\n const T1h = u64.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]);\n const T1l = T1ll | 0;\n // S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39)\n const sigma0h = u64.rotrSH(Ah, Al, 28) ^ u64.rotrBH(Ah, Al, 34) ^ u64.rotrBH(Ah, Al, 39);\n const sigma0l = u64.rotrSL(Ah, Al, 28) ^ u64.rotrBL(Ah, Al, 34) ^ u64.rotrBL(Ah, Al, 39);\n const MAJh = (Ah & Bh) ^ (Ah & Ch) ^ (Bh & Ch);\n const MAJl = (Al & Bl) ^ (Al & Cl) ^ (Bl & Cl);\n Hh = Gh | 0;\n Hl = Gl | 0;\n Gh = Fh | 0;\n Gl = Fl | 0;\n Fh = Eh | 0;\n Fl = El | 0;\n ({ h: Eh, l: El } = u64.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));\n Dh = Ch | 0;\n Dl = Cl | 0;\n Ch = Bh | 0;\n Cl = Bl | 0;\n Bh = Ah | 0;\n Bl = Al | 0;\n const All = u64.add3L(T1l, sigma0l, MAJl);\n Ah = u64.add3H(All, T1h, sigma0h, MAJh);\n Al = All | 0;\n }\n // Add the compressed chunk to the current hash value\n ({ h: Ah, l: Al } = u64.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));\n ({ h: Bh, l: Bl } = u64.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));\n ({ h: Ch, l: Cl } = u64.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));\n ({ h: Dh, l: Dl } = u64.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));\n ({ h: Eh, l: El } = u64.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));\n ({ h: Fh, l: Fl } = u64.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));\n ({ h: Gh, l: Gl } = u64.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));\n ({ h: Hh, l: Hl } = u64.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));\n this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);\n }\n protected roundClean(): void {\n SHA512_W_H.fill(0);\n SHA512_W_L.fill(0);\n }\n destroy(): void {\n this.buffer.fill(0);\n this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n }\n}\n\nexport class SHA512_224 extends SHA512 {\n // h -- high 32 bits, l -- low 32 bits\n protected Ah: number = 0x8c3d37c8 | 0;\n protected Al: number = 0x19544da2 | 0;\n protected Bh: number = 0x73e19966 | 0;\n protected Bl: number = 0x89dcd4d6 | 0;\n protected Ch: number = 0x1dfab7ae | 0;\n protected Cl: number = 0x32ff9c82 | 0;\n protected Dh: number = 0x679dd514 | 0;\n protected Dl: number = 0x582f9fcf | 0;\n protected Eh: number = 0x0f6d2b69 | 0;\n protected El: number = 0x7bd44da8 | 0;\n protected Fh: number = 0x77e36f73 | 0;\n protected Fl: number = 0x04c48942 | 0;\n protected Gh: number = 0x3f9d85a8 | 0;\n protected Gl: number = 0x6a1d36c8 | 0;\n protected Hh: number = 0x1112e6ad | 0;\n protected Hl: number = 0x91d692a1 | 0;\n\n constructor() {\n super();\n this.outputLen = 28;\n }\n}\n\nexport class SHA512_256 extends SHA512 {\n // h -- high 32 bits, l -- low 32 bits\n protected Ah: number = 0x22312194 | 0;\n protected Al: number = 0xfc2bf72c | 0;\n protected Bh: number = 0x9f555fa3 | 0;\n protected Bl: number = 0xc84c64c2 | 0;\n protected Ch: number = 0x2393b86b | 0;\n protected Cl: number = 0x6f53b151 | 0;\n protected Dh: number = 0x96387719 | 0;\n protected Dl: number = 0x5940eabd | 0;\n protected Eh: number = 0x96283ee2 | 0;\n protected El: number = 0xa88effe3 | 0;\n protected Fh: number = 0xbe5e1e25 | 0;\n protected Fl: number = 0x53863992 | 0;\n protected Gh: number = 0x2b0199fc | 0;\n protected Gl: number = 0x2c85b8aa | 0;\n protected Hh: number = 0x0eb72ddc | 0;\n protected Hl: number = 0x81c52ca2 | 0;\n\n constructor() {\n super();\n this.outputLen = 32;\n }\n}\n\nexport class SHA384 extends SHA512 {\n // h -- high 32 bits, l -- low 32 bits\n protected Ah: number = 0xcbbb9d5d | 0;\n protected Al: number = 0xc1059ed8 | 0;\n protected Bh: number = 0x629a292a | 0;\n protected Bl: number = 0x367cd507 | 0;\n protected Ch: number = 0x9159015a | 0;\n protected Cl: number = 0x3070dd17 | 0;\n protected Dh: number = 0x152fecd8 | 0;\n protected Dl: number = 0xf70e5939 | 0;\n protected Eh: number = 0x67332667 | 0;\n protected El: number = 0xffc00b31 | 0;\n protected Fh: number = 0x8eb44a87 | 0;\n protected Fl: number = 0x68581511 | 0;\n protected Gh: number = 0xdb0c2e0d | 0;\n protected Gl: number = 0x64f98fa7 | 0;\n protected Hh: number = 0x47b5481d | 0;\n protected Hl: number = 0xbefa4fa4 | 0;\n\n constructor() {\n super();\n this.outputLen = 48;\n }\n}\n\n/** SHA2-512 hash function. */\nexport const sha512: CHash = /* @__PURE__ */ wrapConstructor(() => new SHA512());\n/** SHA2-512/224 \"truncated\" hash function, with improved resistance to length extension attacks. */\nexport const sha512_224: CHash = /* @__PURE__ */ wrapConstructor(() => new SHA512_224());\n/** SHA2-512/256 \"truncated\" hash function, with improved resistance to length extension attacks. */\nexport const sha512_256: CHash = /* @__PURE__ */ wrapConstructor(() => new SHA512_256());\n/** SHA2-384 hash function. */\nexport const sha384: CHash = /* @__PURE__ */ wrapConstructor(() => new SHA384());\n","/**\n * Hex, bytes and number utilities.\n * @module\n */\n/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */\n\n// 100 lines of code in the file are duplicated from noble-hashes (utils).\n// This is OK: `abstract` directory does not use noble-hashes.\n// User may opt-in into using different hashing library. This way, noble-hashes\n// won't be included into their bundle.\nconst _0n = /* @__PURE__ */ BigInt(0);\nconst _1n = /* @__PURE__ */ BigInt(1);\nconst _2n = /* @__PURE__ */ BigInt(2);\nexport type Hex = Uint8Array | string; // hex strings are accepted for simplicity\nexport type PrivKey = Hex | bigint; // bigints are accepted to ease learning curve\nexport type CHash = {\n (message: Uint8Array | string): Uint8Array;\n blockLen: number;\n outputLen: number;\n create(opts?: { dkLen?: number }): any; // For shake\n};\nexport type FHash = (message: Uint8Array | string) => Uint8Array;\n\nexport function isBytes(a: unknown): a is Uint8Array {\n return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\n}\n\nexport function abytes(item: unknown): void {\n if (!isBytes(item)) throw new Error('Uint8Array expected');\n}\n\nexport function abool(title: string, value: boolean): void {\n if (typeof value !== 'boolean') throw new Error(title + ' boolean expected, got ' + value);\n}\n\n// Array where index 0xf0 (240) is mapped to string 'f0'\nconst hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>\n i.toString(16).padStart(2, '0')\n);\n/**\n * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n abytes(bytes);\n // pre-caching improves the speed 6x\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n hex += hexes[bytes[i]];\n }\n return hex;\n}\n\nexport function numberToHexUnpadded(num: number | bigint): string {\n const hex = num.toString(16);\n return hex.length & 1 ? '0' + hex : hex;\n}\n\nexport function hexToNumber(hex: string): bigint {\n if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);\n return hex === '' ? _0n : BigInt('0x' + hex); // Big Endian\n}\n\n// We use optimized technique to convert hex string to byte array\nconst asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 } as const;\nfunction asciiToBase16(ch: number): number | undefined {\n if (ch >= asciis._0 && ch <= asciis._9) return ch - asciis._0; // '2' => 50-48\n if (ch >= asciis.A && ch <= asciis.F) return ch - (asciis.A - 10); // 'B' => 66-(65-10)\n if (ch >= asciis.a && ch <= asciis.f) return ch - (asciis.a - 10); // 'b' => 98-(97-10)\n return;\n}\n\n/**\n * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])\n */\nexport function hexToBytes(hex: string): Uint8Array {\n if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);\n const hl = hex.length;\n const al = hl / 2;\n if (hl % 2) throw new Error('hex string expected, got unpadded hex of length ' + hl);\n const array = new Uint8Array(al);\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\n const n1 = asciiToBase16(hex.charCodeAt(hi));\n const n2 = asciiToBase16(hex.charCodeAt(hi + 1));\n if (n1 === undefined || n2 === undefined) {\n const char = hex[hi] + hex[hi + 1];\n throw new Error('hex string expected, got non-hex character \"' + char + '\" at index ' + hi);\n }\n array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163\n }\n return array;\n}\n\n// BE: Big Endian, LE: Little Endian\nexport function bytesToNumberBE(bytes: Uint8Array): bigint {\n return hexToNumber(bytesToHex(bytes));\n}\nexport function bytesToNumberLE(bytes: Uint8Array): bigint {\n abytes(bytes);\n return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));\n}\n\nexport function numberToBytesBE(n: number | bigint, len: number): Uint8Array {\n return hexToBytes(n.toString(16).padStart(len * 2, '0'));\n}\nexport function numberToBytesLE(n: number | bigint, len: number): Uint8Array {\n return numberToBytesBE(n, len).reverse();\n}\n// Unpadded, rarely used\nexport function numberToVarBytesBE(n: number | bigint): Uint8Array {\n return hexToBytes(numberToHexUnpadded(n));\n}\n\n/**\n * Takes hex string or Uint8Array, converts to Uint8Array.\n * Validates output length.\n * Will throw error for other types.\n * @param title descriptive title for an error e.g. 'private key'\n * @param hex hex string or Uint8Array\n * @param expectedLength optional, will compare to result array's length\n * @returns\n */\nexport function ensureBytes(title: string, hex: Hex, expectedLength?: number): Uint8Array {\n let res: Uint8Array;\n if (typeof hex === 'string') {\n try {\n res = hexToBytes(hex);\n } catch (e) {\n throw new Error(title + ' must be hex string or Uint8Array, cause: ' + e);\n }\n } else if (isBytes(hex)) {\n // Uint8Array.from() instead of hash.slice() because node.js Buffer\n // is instance of Uint8Array, and its slice() creates **mutable** copy\n res = Uint8Array.from(hex);\n } else {\n throw new Error(title + ' must be hex string or Uint8Array');\n }\n const len = res.length;\n if (typeof expectedLength === 'number' && len !== expectedLength)\n throw new Error(title + ' of length ' + expectedLength + ' expected, got ' + len);\n return res;\n}\n\n/**\n * Copies several Uint8Arrays into one.\n */\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\n let sum = 0;\n for (let i = 0; i < arrays.length; i++) {\n const a = arrays[i];\n abytes(a);\n sum += a.length;\n }\n const res = new Uint8Array(sum);\n for (let i = 0, pad = 0; i < arrays.length; i++) {\n const a = arrays[i];\n res.set(a, pad);\n pad += a.length;\n }\n return res;\n}\n\n// Compares 2 u8a-s in kinda constant time\nexport function equalBytes(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];\n return diff === 0;\n}\n\n// Global symbols in both browsers and Node.js since v11\n// See https://github.com/microsoft/TypeScript/issues/31535\ndeclare const TextEncoder: any;\n\n/**\n * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])\n */\nexport function utf8ToBytes(str: string): Uint8Array {\n if (typeof str !== 'string') throw new Error('string expected');\n return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809\n}\n\n// Is positive bigint\nconst isPosBig = (n: bigint) => typeof n === 'bigint' && _0n <= n;\n\nexport function inRange(n: bigint, min: bigint, max: bigint): boolean {\n return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max;\n}\n\n/**\n * Asserts min <= n < max. NOTE: It's < max and not <= max.\n * @example\n * aInRange('x', x, 1n, 256n); // would assume x is in (1n..255n)\n */\nexport function aInRange(title: string, n: bigint, min: bigint, max: bigint): void {\n // Why min <= n < max and not a (min < n < max) OR b (min <= n <= max)?\n // consider P=256n, min=0n, max=P\n // - a for min=0 would require -1: `inRange('x', x, -1n, P)`\n // - b would commonly require subtraction: `inRange('x', x, 0n, P - 1n)`\n // - our way is the cleanest: `inRange('x', x, 0n, P)\n if (!inRange(n, min, max))\n throw new Error('expected valid ' + title + ': ' + min + ' <= n < ' + max + ', got ' + n);\n}\n\n// Bit operations\n\n/**\n * Calculates amount of bits in a bigint.\n * Same as `n.toString(2).length`\n */\nexport function bitLen(n: bigint): number {\n let len;\n for (len = 0; n > _0n; n >>= _1n, len += 1);\n return len;\n}\n\n/**\n * Gets single bit at position.\n * NOTE: first bit position is 0 (same as arrays)\n * Same as `!!+Array.from(n.toString(2)).reverse()[pos]`\n */\nexport function bitGet(n: bigint, pos: number): bigint {\n return (n >> BigInt(pos)) & _1n;\n}\n\n/**\n * Sets single bit at position.\n */\nexport function bitSet(n: bigint, pos: number, value: boolean): bigint {\n return n | ((value ? _1n : _0n) << BigInt(pos));\n}\n\n/**\n * Calculate mask for N bits. Not using ** operator with bigints because of old engines.\n * Same as BigInt(`0b${Array(i).fill('1').join('')}`)\n */\nexport const bitMask = (n: number): bigint => (_2n << BigInt(n - 1)) - _1n;\n\n// DRBG\n\nconst u8n = (data?: any) => new Uint8Array(data); // creates Uint8Array\nconst u8fr = (arr: any) => Uint8Array.from(arr); // another shortcut\ntype Pred = (v: Uint8Array) => T | undefined;\n/**\n * Minimal HMAC-DRBG from NIST 800-90 for RFC6979 sigs.\n * @returns function that will call DRBG until 2nd arg returns something meaningful\n * @example\n * const drbg = createHmacDRBG(32, 32, hmac);\n * drbg(seed, bytesToKey); // bytesToKey must return Key or undefined\n */\nexport function createHmacDrbg(\n hashLen: number,\n qByteLen: number,\n hmacFn: (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array\n): (seed: Uint8Array, predicate: Pred) => T {\n if (typeof hashLen !== 'number' || hashLen < 2) throw new Error('hashLen must be a number');\n if (typeof qByteLen !== 'number' || qByteLen < 2) throw new Error('qByteLen must be a number');\n if (typeof hmacFn !== 'function') throw new Error('hmacFn must be a function');\n // Step B, Step C: set hashLen to 8*ceil(hlen/8)\n let v = u8n(hashLen); // Minimal non-full-spec HMAC-DRBG from NIST 800-90 for RFC6979 sigs.\n let k = u8n(hashLen); // Steps B and C of RFC6979 3.2: set hashLen, in our case always same\n let i = 0; // Iterations counter, will throw when over 1000\n const reset = () => {\n v.fill(1);\n k.fill(0);\n i = 0;\n };\n const h = (...b: Uint8Array[]) => hmacFn(k, v, ...b); // hmac(k)(v, ...values)\n const reseed = (seed = u8n()) => {\n // HMAC-DRBG reseed() function. Steps D-G\n k = h(u8fr([0x00]), seed); // k = hmac(k || v || 0x00 || seed)\n v = h(); // v = hmac(k || v)\n if (seed.length === 0) return;\n k = h(u8fr([0x01]), seed); // k = hmac(k || v || 0x01 || seed)\n v = h(); // v = hmac(k || v)\n };\n const gen = () => {\n // HMAC-DRBG generate() function\n if (i++ >= 1000) throw new Error('drbg: tried 1000 values');\n let len = 0;\n const out: Uint8Array[] = [];\n while (len < qByteLen) {\n v = h();\n const sl = v.slice();\n out.push(sl);\n len += v.length;\n }\n return concatBytes(...out);\n };\n const genUntil = (seed: Uint8Array, pred: Pred): T => {\n reset();\n reseed(seed); // Steps D-G\n let res: T | undefined = undefined; // Step H: grind until k is in [1..n-1]\n while (!(res = pred(gen()))) reseed();\n reset();\n return res;\n };\n return genUntil;\n}\n\n// Validating curves and fields\n\nconst validatorFns = {\n bigint: (val: any): boolean => typeof val === 'bigint',\n function: (val: any): boolean => typeof val === 'function',\n boolean: (val: any): boolean => typeof val === 'boolean',\n string: (val: any): boolean => typeof val === 'string',\n stringOrUint8Array: (val: any): boolean => typeof val === 'string' || isBytes(val),\n isSafeInteger: (val: any): boolean => Number.isSafeInteger(val),\n array: (val: any): boolean => Array.isArray(val),\n field: (val: any, object: any): any => (object as any).Fp.isValid(val),\n hash: (val: any): boolean => typeof val === 'function' && Number.isSafeInteger(val.outputLen),\n} as const;\ntype Validator = keyof typeof validatorFns;\ntype ValMap> = { [K in keyof T]?: Validator };\n// type Record = { [P in K]: T; }\n\nexport function validateObject>(\n object: T,\n validators: ValMap,\n optValidators: ValMap = {}\n): T {\n const checkField = (fieldName: keyof T, type: Validator, isOptional: boolean) => {\n const checkVal = validatorFns[type];\n if (typeof checkVal !== 'function') throw new Error('invalid validator function');\n\n const val = object[fieldName as keyof typeof object];\n if (isOptional && val === undefined) return;\n if (!checkVal(val, object)) {\n throw new Error(\n 'param ' + String(fieldName) + ' is invalid. Expected ' + type + ', got ' + val\n );\n }\n };\n for (const [fieldName, type] of Object.entries(validators)) checkField(fieldName, type!, false);\n for (const [fieldName, type] of Object.entries(optValidators)) checkField(fieldName, type!, true);\n return object;\n}\n// validate type tests\n// const o: { a: number; b: number; c: number } = { a: 1, b: 5, c: 6 };\n// const z0 = validateObject(o, { a: 'isSafeInteger' }, { c: 'bigint' }); // Ok!\n// // Should fail type-check\n// const z1 = validateObject(o, { a: 'tmp' }, { c: 'zz' });\n// const z2 = validateObject(o, { a: 'isSafeInteger' }, { c: 'zz' });\n// const z3 = validateObject(o, { test: 'boolean', z: 'bug' });\n// const z4 = validateObject(o, { a: 'boolean', z: 'bug' });\n\n/**\n * throws not implemented error\n */\nexport const notImplemented = (): never => {\n throw new Error('not implemented');\n};\n\n/**\n * Memoizes (caches) computation result.\n * Uses WeakMap: the value is going auto-cleaned by GC after last reference is removed.\n */\nexport function memoized(\n fn: (arg: T, ...args: O) => R\n): (arg: T, ...args: O) => R {\n const map = new WeakMap();\n return (arg: T, ...args: O): R => {\n const val = map.get(arg);\n if (val !== undefined) return val;\n const computed = fn(arg, ...args);\n map.set(arg, computed);\n return computed;\n };\n}\n","/**\n * Utils for modular division and finite fields.\n * A finite field over 11 is integer number operations `mod 11`.\n * There is no division: it is replaced by modular multiplicative inverse.\n * @module\n */\n/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */\nimport {\n bitMask,\n bytesToNumberBE,\n bytesToNumberLE,\n ensureBytes,\n numberToBytesBE,\n numberToBytesLE,\n validateObject,\n} from './utils.js';\n\n// prettier-ignore\nconst _0n = BigInt(0), _1n = BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);\n// prettier-ignore\nconst _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5), _8n = /* @__PURE__ */ BigInt(8);\n// prettier-ignore\nconst _9n =/* @__PURE__ */ BigInt(9), _16n = /* @__PURE__ */ BigInt(16);\n\n// Calculates a modulo b\nexport function mod(a: bigint, b: bigint): bigint {\n const result = a % b;\n return result >= _0n ? result : b + result;\n}\n/**\n * Efficiently raise num to power and do modular division.\n * Unsafe in some contexts: uses ladder, so can expose bigint bits.\n * @todo use field version && remove\n * @example\n * pow(2n, 6n, 11n) // 64n % 11n == 9n\n */\nexport function pow(num: bigint, power: bigint, modulo: bigint): bigint {\n if (power < _0n) throw new Error('invalid exponent, negatives unsupported');\n if (modulo <= _0n) throw new Error('invalid modulus');\n if (modulo === _1n) return _0n;\n let res = _1n;\n while (power > _0n) {\n if (power & _1n) res = (res * num) % modulo;\n num = (num * num) % modulo;\n power >>= _1n;\n }\n return res;\n}\n\n/** Does `x^(2^power)` mod p. `pow2(30, 4)` == `30^(2^4)` */\nexport function pow2(x: bigint, power: bigint, modulo: bigint): bigint {\n let res = x;\n while (power-- > _0n) {\n res *= res;\n res %= modulo;\n }\n return res;\n}\n\n/**\n * Inverses number over modulo.\n * Implemented using [Euclidean GCD](https://brilliant.org/wiki/extended-euclidean-algorithm/).\n */\nexport function invert(number: bigint, modulo: bigint): bigint {\n if (number === _0n) throw new Error('invert: expected non-zero number');\n if (modulo <= _0n) throw new Error('invert: expected positive modulus, got ' + modulo);\n // Fermat's little theorem \"CT-like\" version inv(n) = n^(m-2) mod m is 30x slower.\n let a = mod(number, modulo);\n let b = modulo;\n // prettier-ignore\n let x = _0n, y = _1n, u = _1n, v = _0n;\n while (a !== _0n) {\n // JIT applies optimization if those two lines follow each other\n const q = b / a;\n const r = b % a;\n const m = x - u * q;\n const n = y - v * q;\n // prettier-ignore\n b = a, a = r, x = u, y = v, u = m, v = n;\n }\n const gcd = b;\n if (gcd !== _1n) throw new Error('invert: does not exist');\n return mod(x, modulo);\n}\n\n/**\n * Tonelli-Shanks square root search algorithm.\n * 1. https://eprint.iacr.org/2012/685.pdf (page 12)\n * 2. Square Roots from 1; 24, 51, 10 to Dan Shanks\n * Will start an infinite loop if field order P is not prime.\n * @param P field order\n * @returns function that takes field Fp (created from P) and number n\n */\nexport function tonelliShanks(P: bigint): (Fp: IField, n: T) => T {\n // Legendre constant: used to calculate Legendre symbol (a | p),\n // which denotes the value of a^((p-1)/2) (mod p).\n // (a | p) ≡ 1 if a is a square (mod p)\n // (a | p) ≡ -1 if a is not a square (mod p)\n // (a | p) ≡ 0 if a ≡ 0 (mod p)\n const legendreC = (P - _1n) / _2n;\n\n let Q: bigint, S: number, Z: bigint;\n // Step 1: By factoring out powers of 2 from p - 1,\n // find q and s such that p - 1 = q*(2^s) with q odd\n for (Q = P - _1n, S = 0; Q % _2n === _0n; Q /= _2n, S++);\n\n // Step 2: Select a non-square z such that (z | p) ≡ -1 and set c ≡ zq\n for (Z = _2n; Z < P && pow(Z, legendreC, P) !== P - _1n; Z++) {\n // Crash instead of infinity loop, we cannot reasonable count until P.\n if (Z > 1000) throw new Error('Cannot find square root: likely non-prime P');\n }\n\n // Fast-path\n if (S === 1) {\n const p1div4 = (P + _1n) / _4n;\n return function tonelliFast(Fp: IField, n: T) {\n const root = Fp.pow(n, p1div4);\n if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');\n return root;\n };\n }\n\n // Slow-path\n const Q1div2 = (Q + _1n) / _2n;\n return function tonelliSlow(Fp: IField, n: T): T {\n // Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1\n if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE)) throw new Error('Cannot find square root');\n let r = S;\n // TODO: will fail at Fp2/etc\n let g = Fp.pow(Fp.mul(Fp.ONE, Z), Q); // will update both x and b\n let x = Fp.pow(n, Q1div2); // first guess at the square root\n let b = Fp.pow(n, Q); // first guess at the fudge factor\n\n while (!Fp.eql(b, Fp.ONE)) {\n if (Fp.eql(b, Fp.ZERO)) return Fp.ZERO; // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm (4. If t = 0, return r = 0)\n // Find m such b^(2^m)==1\n let m = 1;\n for (let t2 = Fp.sqr(b); m < r; m++) {\n if (Fp.eql(t2, Fp.ONE)) break;\n t2 = Fp.sqr(t2); // t2 *= t2\n }\n // NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift, otherwise there will be overflow\n const ge = Fp.pow(g, _1n << BigInt(r - m - 1)); // ge = 2^(r-m-1)\n g = Fp.sqr(ge); // g = ge * ge\n x = Fp.mul(x, ge); // x *= ge\n b = Fp.mul(b, g); // b *= g\n r = m;\n }\n return x;\n };\n}\n\n/**\n * Square root for a finite field. It will try to check if optimizations are applicable and fall back to 4:\n *\n * 1. P ≡ 3 (mod 4)\n * 2. P ≡ 5 (mod 8)\n * 3. P ≡ 9 (mod 16)\n * 4. Tonelli-Shanks algorithm\n *\n * Different algorithms can give different roots, it is up to user to decide which one they want.\n * For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).\n */\nexport function FpSqrt(P: bigint): (Fp: IField, n: T) => T {\n // P ≡ 3 (mod 4)\n // √n = n^((P+1)/4)\n if (P % _4n === _3n) {\n // Not all roots possible!\n // const ORDER =\n // 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;\n // const NUM = 72057594037927816n;\n const p1div4 = (P + _1n) / _4n;\n return function sqrt3mod4(Fp: IField, n: T) {\n const root = Fp.pow(n, p1div4);\n // Throw if root**2 != n\n if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');\n return root;\n };\n }\n\n // Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)\n if (P % _8n === _5n) {\n const c1 = (P - _5n) / _8n;\n return function sqrt5mod8(Fp: IField, n: T) {\n const n2 = Fp.mul(n, _2n);\n const v = Fp.pow(n2, c1);\n const nv = Fp.mul(n, v);\n const i = Fp.mul(Fp.mul(nv, _2n), v);\n const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));\n if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');\n return root;\n };\n }\n\n // P ≡ 9 (mod 16)\n if (P % _16n === _9n) {\n // NOTE: tonelli is too slow for bls-Fp2 calculations even on start\n // Means we cannot use sqrt for constants at all!\n //\n // const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F\n // const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F\n // const c3 = Fp.sqrt(Fp.negate(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F\n // const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic\n // sqrt = (x) => {\n // let tv1 = Fp.pow(x, c4); // 1. tv1 = x^c4\n // let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1\n // const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1\n // let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1\n // const e1 = Fp.equals(Fp.square(tv2), x); // 5. e1 = (tv2^2) == x\n // const e2 = Fp.equals(Fp.square(tv3), x); // 6. e2 = (tv3^2) == x\n // tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x\n // tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x\n // const e3 = Fp.equals(Fp.square(tv2), x); // 9. e3 = (tv2^2) == x\n // return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2\n // }\n }\n // Other cases: Tonelli-Shanks algorithm\n return tonelliShanks(P);\n}\n\n// Little-endian check for first LE bit (last BE bit);\nexport const isNegativeLE = (num: bigint, modulo: bigint): boolean =>\n (mod(num, modulo) & _1n) === _1n;\n\n/** Field is not always over prime: for example, Fp2 has ORDER(q)=p^m. */\nexport interface IField {\n ORDER: bigint;\n isLE: boolean;\n BYTES: number;\n BITS: number;\n MASK: bigint;\n ZERO: T;\n ONE: T;\n // 1-arg\n create: (num: T) => T;\n isValid: (num: T) => boolean;\n is0: (num: T) => boolean;\n neg(num: T): T;\n inv(num: T): T;\n sqrt(num: T): T;\n sqr(num: T): T;\n // 2-args\n eql(lhs: T, rhs: T): boolean;\n add(lhs: T, rhs: T): T;\n sub(lhs: T, rhs: T): T;\n mul(lhs: T, rhs: T | bigint): T;\n pow(lhs: T, power: bigint): T;\n div(lhs: T, rhs: T | bigint): T;\n // N for NonNormalized (for now)\n addN(lhs: T, rhs: T): T;\n subN(lhs: T, rhs: T): T;\n mulN(lhs: T, rhs: T | bigint): T;\n sqrN(num: T): T;\n\n // Optional\n // Should be same as sgn0 function in\n // [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#section-4.1).\n // NOTE: sgn0 is 'negative in LE', which is same as odd. And negative in LE is kinda strange definition anyway.\n isOdd?(num: T): boolean; // Odd instead of even since we have it for Fp2\n // legendre?(num: T): T;\n pow(lhs: T, power: bigint): T;\n invertBatch: (lst: T[]) => T[];\n toBytes(num: T): Uint8Array;\n fromBytes(bytes: Uint8Array): T;\n // If c is False, CMOV returns a, otherwise it returns b.\n cmov(a: T, b: T, c: boolean): T;\n}\n// prettier-ignore\nconst FIELD_FIELDS = [\n 'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',\n 'eql', 'add', 'sub', 'mul', 'pow', 'div',\n 'addN', 'subN', 'mulN', 'sqrN'\n] as const;\nexport function validateField(field: IField): IField {\n const initial = {\n ORDER: 'bigint',\n MASK: 'bigint',\n BYTES: 'isSafeInteger',\n BITS: 'isSafeInteger',\n } as Record;\n const opts = FIELD_FIELDS.reduce((map, val: string) => {\n map[val] = 'function';\n return map;\n }, initial);\n return validateObject(field, opts);\n}\n\n// Generic field functions\n\n/**\n * Same as `pow` but for Fp: non-constant-time.\n * Unsafe in some contexts: uses ladder, so can expose bigint bits.\n */\nexport function FpPow(f: IField, num: T, power: bigint): T {\n // Should have same speed as pow for bigints\n // TODO: benchmark!\n if (power < _0n) throw new Error('invalid exponent, negatives unsupported');\n if (power === _0n) return f.ONE;\n if (power === _1n) return num;\n let p = f.ONE;\n let d = num;\n while (power > _0n) {\n if (power & _1n) p = f.mul(p, d);\n d = f.sqr(d);\n power >>= _1n;\n }\n return p;\n}\n\n/**\n * Efficiently invert an array of Field elements.\n * `inv(0)` will return `undefined` here: make sure to throw an error.\n */\nexport function FpInvertBatch(f: IField, nums: T[]): T[] {\n const tmp = new Array(nums.length);\n // Walk from first to last, multiply them by each other MOD p\n const lastMultiplied = nums.reduce((acc, num, i) => {\n if (f.is0(num)) return acc;\n tmp[i] = acc;\n return f.mul(acc, num);\n }, f.ONE);\n // Invert last element\n const inverted = f.inv(lastMultiplied);\n // Walk from last to first, multiply them by inverted each other MOD p\n nums.reduceRight((acc, num, i) => {\n if (f.is0(num)) return acc;\n tmp[i] = f.mul(acc, tmp[i]);\n return f.mul(acc, num);\n }, inverted);\n return tmp;\n}\n\nexport function FpDiv(f: IField, lhs: T, rhs: T | bigint): T {\n return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));\n}\n\n/**\n * Legendre symbol.\n * * (a | p) ≡ 1 if a is a square (mod p), quadratic residue\n * * (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue\n * * (a | p) ≡ 0 if a ≡ 0 (mod p)\n */\nexport function FpLegendre(order: bigint): (f: IField, x: T) => T {\n const legendreConst = (order - _1n) / _2n; // Integer arithmetic\n return (f: IField, x: T): T => f.pow(x, legendreConst);\n}\n\n// This function returns True whenever the value x is a square in the field F.\nexport function FpIsSquare(f: IField): (x: T) => boolean {\n const legendre = FpLegendre(f.ORDER);\n return (x: T): boolean => {\n const p = legendre(f, x);\n return f.eql(p, f.ZERO) || f.eql(p, f.ONE);\n };\n}\n\n// CURVE.n lengths\nexport function nLength(\n n: bigint,\n nBitLength?: number\n): {\n nBitLength: number;\n nByteLength: number;\n} {\n // Bit size, byte size of CURVE.n\n const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;\n const nByteLength = Math.ceil(_nBitLength / 8);\n return { nBitLength: _nBitLength, nByteLength };\n}\n\ntype FpField = IField & Required, 'isOdd'>>;\n/**\n * Initializes a finite field over prime.\n * Major performance optimizations:\n * * a) denormalized operations like mulN instead of mul\n * * b) same object shape: never add or remove keys\n * * c) Object.freeze\n * Fragile: always run a benchmark on a change.\n * Security note: operations don't check 'isValid' for all elements for performance reasons,\n * it is caller responsibility to check this.\n * This is low-level code, please make sure you know what you're doing.\n * @param ORDER prime positive bigint\n * @param bitLen how many bits the field consumes\n * @param isLE (def: false) if encoding / decoding should be in little-endian\n * @param redef optional faster redefinitions of sqrt and other methods\n */\nexport function Field(\n ORDER: bigint,\n bitLen?: number,\n isLE = false,\n redef: Partial> = {}\n): Readonly {\n if (ORDER <= _0n) throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);\n const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);\n if (BYTES > 2048) throw new Error('invalid field: expected ORDER of <= 2048 bytes');\n let sqrtP: ReturnType; // cached sqrtP\n const f: Readonly = Object.freeze({\n ORDER,\n isLE,\n BITS,\n BYTES,\n MASK: bitMask(BITS),\n ZERO: _0n,\n ONE: _1n,\n create: (num) => mod(num, ORDER),\n isValid: (num) => {\n if (typeof num !== 'bigint')\n throw new Error('invalid field element: expected bigint, got ' + typeof num);\n return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible\n },\n is0: (num) => num === _0n,\n isOdd: (num) => (num & _1n) === _1n,\n neg: (num) => mod(-num, ORDER),\n eql: (lhs, rhs) => lhs === rhs,\n\n sqr: (num) => mod(num * num, ORDER),\n add: (lhs, rhs) => mod(lhs + rhs, ORDER),\n sub: (lhs, rhs) => mod(lhs - rhs, ORDER),\n mul: (lhs, rhs) => mod(lhs * rhs, ORDER),\n pow: (num, power) => FpPow(f, num, power),\n div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),\n\n // Same as above, but doesn't normalize\n sqrN: (num) => num * num,\n addN: (lhs, rhs) => lhs + rhs,\n subN: (lhs, rhs) => lhs - rhs,\n mulN: (lhs, rhs) => lhs * rhs,\n\n inv: (num) => invert(num, ORDER),\n sqrt:\n redef.sqrt ||\n ((n) => {\n if (!sqrtP) sqrtP = FpSqrt(ORDER);\n return sqrtP(f, n);\n }),\n invertBatch: (lst) => FpInvertBatch(f, lst),\n // TODO: do we really need constant cmov?\n // We don't have const-time bigints anyway, so probably will be not very useful\n cmov: (a, b, c) => (c ? b : a),\n toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES)),\n fromBytes: (bytes) => {\n if (bytes.length !== BYTES)\n throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);\n return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);\n },\n } as FpField);\n return Object.freeze(f);\n}\n\nexport function FpSqrtOdd(Fp: IField, elm: T): T {\n if (!Fp.isOdd) throw new Error(\"Field doesn't have isOdd\");\n const root = Fp.sqrt(elm);\n return Fp.isOdd(root) ? root : Fp.neg(root);\n}\n\nexport function FpSqrtEven(Fp: IField, elm: T): T {\n if (!Fp.isOdd) throw new Error(\"Field doesn't have isOdd\");\n const root = Fp.sqrt(elm);\n return Fp.isOdd(root) ? Fp.neg(root) : root;\n}\n\n/**\n * \"Constant-time\" private key generation utility.\n * Same as mapKeyToField, but accepts less bytes (40 instead of 48 for 32-byte field).\n * Which makes it slightly more biased, less secure.\n * @deprecated use `mapKeyToField` instead\n */\nexport function hashToPrivateScalar(\n hash: string | Uint8Array,\n groupOrder: bigint,\n isLE = false\n): bigint {\n hash = ensureBytes('privateHash', hash);\n const hashLen = hash.length;\n const minLen = nLength(groupOrder).nByteLength + 8;\n if (minLen < 24 || hashLen < minLen || hashLen > 1024)\n throw new Error(\n 'hashToPrivateScalar: expected ' + minLen + '-1024 bytes of input, got ' + hashLen\n );\n const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);\n return mod(num, groupOrder - _1n) + _1n;\n}\n\n/**\n * Returns total number of bytes consumed by the field element.\n * For example, 32 bytes for usual 256-bit weierstrass curve.\n * @param fieldOrder number of field elements, usually CURVE.n\n * @returns byte length of field\n */\nexport function getFieldBytesLength(fieldOrder: bigint): number {\n if (typeof fieldOrder !== 'bigint') throw new Error('field order must be bigint');\n const bitLength = fieldOrder.toString(2).length;\n return Math.ceil(bitLength / 8);\n}\n\n/**\n * Returns minimal amount of bytes that can be safely reduced\n * by field order.\n * Should be 2^-128 for 128-bit curve such as P256.\n * @param fieldOrder number of field elements, usually CURVE.n\n * @returns byte length of target hash\n */\nexport function getMinHashLength(fieldOrder: bigint): number {\n const length = getFieldBytesLength(fieldOrder);\n return length + Math.ceil(length / 2);\n}\n\n/**\n * \"Constant-time\" private key generation utility.\n * Can take (n + n/2) or more bytes of uniform input e.g. from CSPRNG or KDF\n * and convert them into private scalar, with the modulo bias being negligible.\n * Needs at least 48 bytes of input for 32-byte private key.\n * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/\n * FIPS 186-5, A.2 https://csrc.nist.gov/publications/detail/fips/186/5/final\n * RFC 9380, https://www.rfc-editor.org/rfc/rfc9380#section-5\n * @param hash hash output from SHA3 or a similar function\n * @param groupOrder size of subgroup - (e.g. secp256k1.CURVE.n)\n * @param isLE interpret hash bytes as LE num\n * @returns valid private scalar\n */\nexport function mapHashToField(key: Uint8Array, fieldOrder: bigint, isLE = false): Uint8Array {\n const len = key.length;\n const fieldLen = getFieldBytesLength(fieldOrder);\n const minLen = getMinHashLength(fieldOrder);\n // No small numbers: need to understand bias story. No huge numbers: easier to detect JS timings.\n if (len < 16 || len < minLen || len > 1024)\n throw new Error('expected ' + minLen + '-1024 bytes of input, got ' + len);\n const num = isLE ? bytesToNumberLE(key) : bytesToNumberBE(key);\n // `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0\n const reduced = mod(num, fieldOrder - _1n) + _1n;\n return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);\n}\n","/**\n * Methods for elliptic curve multiplication by scalars.\n * Contains wNAF, pippenger\n * @module\n */\n/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */\nimport { type IField, nLength, validateField } from './modular.js';\nimport { bitLen, validateObject } from './utils.js';\n\nconst _0n = BigInt(0);\nconst _1n = BigInt(1);\n\nexport type AffinePoint = {\n x: T;\n y: T;\n} & { z?: never; t?: never };\n\nexport interface Group> {\n double(): T;\n negate(): T;\n add(other: T): T;\n subtract(other: T): T;\n equals(other: T): boolean;\n multiply(scalar: bigint): T;\n}\n\nexport type GroupConstructor = {\n BASE: T;\n ZERO: T;\n};\nexport type Mapper = (i: T[]) => T[];\n\nfunction constTimeNegate>(condition: boolean, item: T): T {\n const neg = item.negate();\n return condition ? neg : item;\n}\n\nfunction validateW(W: number, bits: number) {\n if (!Number.isSafeInteger(W) || W <= 0 || W > bits)\n throw new Error('invalid window size, expected [1..' + bits + '], got W=' + W);\n}\n\nfunction calcWOpts(W: number, bits: number) {\n validateW(W, bits);\n const windows = Math.ceil(bits / W) + 1; // +1, because\n const windowSize = 2 ** (W - 1); // -1 because we skip zero\n return { windows, windowSize };\n}\n\nfunction validateMSMPoints(points: any[], c: any) {\n if (!Array.isArray(points)) throw new Error('array expected');\n points.forEach((p, i) => {\n if (!(p instanceof c)) throw new Error('invalid point at index ' + i);\n });\n}\nfunction validateMSMScalars(scalars: any[], field: any) {\n if (!Array.isArray(scalars)) throw new Error('array of scalars expected');\n scalars.forEach((s, i) => {\n if (!field.isValid(s)) throw new Error('invalid scalar at index ' + i);\n });\n}\n\n// Since points in different groups cannot be equal (different object constructor),\n// we can have single place to store precomputes\nconst pointPrecomputes = new WeakMap();\nconst pointWindowSizes = new WeakMap(); // This allows use make points immutable (nothing changes inside)\n\nfunction getW(P: any): number {\n return pointWindowSizes.get(P) || 1;\n}\n\nexport type IWNAF> = {\n constTimeNegate: >(condition: boolean, item: T) => T;\n hasPrecomputes(elm: T): boolean;\n unsafeLadder(elm: T, n: bigint, p?: T): T;\n precomputeWindow(elm: T, W: number): Group[];\n wNAF(W: number, precomputes: T[], n: bigint): { p: T; f: T };\n wNAFUnsafe(W: number, precomputes: T[], n: bigint, acc?: T): T;\n getPrecomputes(W: number, P: T, transform: Mapper): T[];\n wNAFCached(P: T, n: bigint, transform: Mapper): { p: T; f: T };\n wNAFCachedUnsafe(P: T, n: bigint, transform: Mapper, prev?: T): T;\n setWindowSize(P: T, W: number): void;\n};\n\n/**\n * Elliptic curve multiplication of Point by scalar. Fragile.\n * Scalars should always be less than curve order: this should be checked inside of a curve itself.\n * Creates precomputation tables for fast multiplication:\n * - private scalar is split by fixed size windows of W bits\n * - every window point is collected from window's table & added to accumulator\n * - since windows are different, same point inside tables won't be accessed more than once per calc\n * - each multiplication is 'Math.ceil(CURVE_ORDER / 𝑊) + 1' point additions (fixed for any scalar)\n * - +1 window is neccessary for wNAF\n * - wNAF reduces table size: 2x less memory + 2x faster generation, but 10% slower multiplication\n *\n * @todo Research returning 2d JS array of windows, instead of a single window.\n * This would allow windows to be in different memory locations\n */\nexport function wNAF>(c: GroupConstructor, bits: number): IWNAF {\n return {\n constTimeNegate,\n\n hasPrecomputes(elm: T) {\n return getW(elm) !== 1;\n },\n\n // non-const time multiplication ladder\n unsafeLadder(elm: T, n: bigint, p = c.ZERO) {\n let d: T = elm;\n while (n > _0n) {\n if (n & _1n) p = p.add(d);\n d = d.double();\n n >>= _1n;\n }\n return p;\n },\n\n /**\n * Creates a wNAF precomputation window. Used for caching.\n * Default window size is set by `utils.precompute()` and is equal to 8.\n * Number of precomputed points depends on the curve size:\n * 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:\n * - 𝑊 is the window size\n * - 𝑛 is the bitlength of the curve order.\n * For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.\n * @param elm Point instance\n * @param W window size\n * @returns precomputed point tables flattened to a single array\n */\n precomputeWindow(elm: T, W: number): Group[] {\n const { windows, windowSize } = calcWOpts(W, bits);\n const points: T[] = [];\n let p: T = elm;\n let base = p;\n for (let window = 0; window < windows; window++) {\n base = p;\n points.push(base);\n // =1, because we skip zero\n for (let i = 1; i < windowSize; i++) {\n base = base.add(p);\n points.push(base);\n }\n p = base.double();\n }\n return points;\n },\n\n /**\n * Implements ec multiplication using precomputed tables and w-ary non-adjacent form.\n * @param W window size\n * @param precomputes precomputed tables\n * @param n scalar (we don't check here, but should be less than curve order)\n * @returns real and fake (for const-time) points\n */\n wNAF(W: number, precomputes: T[], n: bigint): { p: T; f: T } {\n // TODO: maybe check that scalar is less than group order? wNAF behavious is undefined otherwise\n // But need to carefully remove other checks before wNAF. ORDER == bits here\n const { windows, windowSize } = calcWOpts(W, bits);\n\n let p = c.ZERO;\n let f = c.BASE;\n\n const mask = BigInt(2 ** W - 1); // Create mask with W ones: 0b1111 for W=4 etc.\n const maxNumber = 2 ** W;\n const shiftBy = BigInt(W);\n\n for (let window = 0; window < windows; window++) {\n const offset = window * windowSize;\n // Extract W bits.\n let wbits = Number(n & mask);\n\n // Shift number by W bits.\n n >>= shiftBy;\n\n // If the bits are bigger than max size, we'll split those.\n // +224 => 256 - 32\n if (wbits > windowSize) {\n wbits -= maxNumber;\n n += _1n;\n }\n\n // This code was first written with assumption that 'f' and 'p' will never be infinity point:\n // since each addition is multiplied by 2 ** W, it cannot cancel each other. However,\n // there is negate now: it is possible that negated element from low value\n // would be the same as high element, which will create carry into next window.\n // It's not obvious how this can fail, but still worth investigating later.\n\n // Check if we're onto Zero point.\n // Add random point inside current window to f.\n const offset1 = offset;\n const offset2 = offset + Math.abs(wbits) - 1; // -1 because we skip zero\n const cond1 = window % 2 !== 0;\n const cond2 = wbits < 0;\n if (wbits === 0) {\n // The most important part for const-time getPublicKey\n f = f.add(constTimeNegate(cond1, precomputes[offset1]));\n } else {\n p = p.add(constTimeNegate(cond2, precomputes[offset2]));\n }\n }\n // JIT-compiler should not eliminate f here, since it will later be used in normalizeZ()\n // Even if the variable is still unused, there are some checks which will\n // throw an exception, so compiler needs to prove they won't happen, which is hard.\n // At this point there is a way to F be infinity-point even if p is not,\n // which makes it less const-time: around 1 bigint multiply.\n return { p, f };\n },\n\n /**\n * Implements ec unsafe (non const-time) multiplication using precomputed tables and w-ary non-adjacent form.\n * @param W window size\n * @param precomputes precomputed tables\n * @param n scalar (we don't check here, but should be less than curve order)\n * @param acc accumulator point to add result of multiplication\n * @returns point\n */\n wNAFUnsafe(W: number, precomputes: T[], n: bigint, acc: T = c.ZERO): T {\n const { windows, windowSize } = calcWOpts(W, bits);\n const mask = BigInt(2 ** W - 1); // Create mask with W ones: 0b1111 for W=4 etc.\n const maxNumber = 2 ** W;\n const shiftBy = BigInt(W);\n for (let window = 0; window < windows; window++) {\n const offset = window * windowSize;\n if (n === _0n) break; // No need to go over empty scalar\n // Extract W bits.\n let wbits = Number(n & mask);\n // Shift number by W bits.\n n >>= shiftBy;\n // If the bits are bigger than max size, we'll split those.\n // +224 => 256 - 32\n if (wbits > windowSize) {\n wbits -= maxNumber;\n n += _1n;\n }\n if (wbits === 0) continue;\n let curr = precomputes[offset + Math.abs(wbits) - 1]; // -1 because we skip zero\n if (wbits < 0) curr = curr.negate();\n // NOTE: by re-using acc, we can save a lot of additions in case of MSM\n acc = acc.add(curr);\n }\n return acc;\n },\n\n getPrecomputes(W: number, P: T, transform: Mapper): T[] {\n // Calculate precomputes on a first run, reuse them after\n let comp = pointPrecomputes.get(P);\n if (!comp) {\n comp = this.precomputeWindow(P, W) as T[];\n if (W !== 1) pointPrecomputes.set(P, transform(comp));\n }\n return comp;\n },\n\n wNAFCached(P: T, n: bigint, transform: Mapper): { p: T; f: T } {\n const W = getW(P);\n return this.wNAF(W, this.getPrecomputes(W, P, transform), n);\n },\n\n wNAFCachedUnsafe(P: T, n: bigint, transform: Mapper, prev?: T): T {\n const W = getW(P);\n if (W === 1) return this.unsafeLadder(P, n, prev); // For W=1 ladder is ~x2 faster\n return this.wNAFUnsafe(W, this.getPrecomputes(W, P, transform), n, prev);\n },\n\n // We calculate precomputes for elliptic curve point multiplication\n // using windowed method. This specifies window size and\n // stores precomputed values. Usually only base point would be precomputed.\n\n setWindowSize(P: T, W: number) {\n validateW(W, bits);\n pointWindowSizes.set(P, W);\n pointPrecomputes.delete(P);\n },\n };\n}\n\n/**\n * Pippenger algorithm for multi-scalar multiplication (MSM, Pa + Qb + Rc + ...).\n * 30x faster vs naive addition on L=4096, 10x faster with precomputes.\n * For N=254bit, L=1, it does: 1024 ADD + 254 DBL. For L=5: 1536 ADD + 254 DBL.\n * Algorithmically constant-time (for same L), even when 1 point + scalar, or when scalar = 0.\n * @param c Curve Point constructor\n * @param fieldN field over CURVE.N - important that it's not over CURVE.P\n * @param points array of L curve points\n * @param scalars array of L scalars (aka private keys / bigints)\n */\nexport function pippenger>(\n c: GroupConstructor,\n fieldN: IField,\n points: T[],\n scalars: bigint[]\n): T {\n // If we split scalars by some window (let's say 8 bits), every chunk will only\n // take 256 buckets even if there are 4096 scalars, also re-uses double.\n // TODO:\n // - https://eprint.iacr.org/2024/750.pdf\n // - https://tches.iacr.org/index.php/TCHES/article/view/10287\n // 0 is accepted in scalars\n validateMSMPoints(points, c);\n validateMSMScalars(scalars, fieldN);\n if (points.length !== scalars.length)\n throw new Error('arrays of points and scalars must have equal length');\n const zero = c.ZERO;\n const wbits = bitLen(BigInt(points.length));\n const windowSize = wbits > 12 ? wbits - 3 : wbits > 4 ? wbits - 2 : wbits ? 2 : 1; // in bits\n const MASK = (1 << windowSize) - 1;\n const buckets = new Array(MASK + 1).fill(zero); // +1 for zero array\n const lastBits = Math.floor((fieldN.BITS - 1) / windowSize) * windowSize;\n let sum = zero;\n for (let i = lastBits; i >= 0; i -= windowSize) {\n buckets.fill(zero);\n for (let j = 0; j < scalars.length; j++) {\n const scalar = scalars[j];\n const wbits = Number((scalar >> BigInt(i)) & BigInt(MASK));\n buckets[wbits] = buckets[wbits].add(points[j]);\n }\n let resI = zero; // not using this will do small speed-up, but will lose ct\n // Skip first bucket, because it is zero\n for (let j = buckets.length - 1, sumI = zero; j > 0; j--) {\n sumI = sumI.add(buckets[j]);\n resI = resI.add(sumI);\n }\n sum = sum.add(resI);\n if (i !== 0) for (let j = 0; j < windowSize; j++) sum = sum.double();\n }\n return sum as T;\n}\n/**\n * Precomputed multi-scalar multiplication (MSM, Pa + Qb + Rc + ...).\n * @param c Curve Point constructor\n * @param fieldN field over CURVE.N - important that it's not over CURVE.P\n * @param points array of L curve points\n * @returns function which multiplies points with scaars\n */\nexport function precomputeMSMUnsafe>(\n c: GroupConstructor,\n fieldN: IField,\n points: T[],\n windowSize: number\n): (scalars: bigint[]) => T {\n /**\n * Performance Analysis of Window-based Precomputation\n *\n * Base Case (256-bit scalar, 8-bit window):\n * - Standard precomputation requires:\n * - 31 additions per scalar × 256 scalars = 7,936 ops\n * - Plus 255 summary additions = 8,191 total ops\n * Note: Summary additions can be optimized via accumulator\n *\n * Chunked Precomputation Analysis:\n * - Using 32 chunks requires:\n * - 255 additions per chunk\n * - 256 doublings\n * - Total: (255 × 32) + 256 = 8,416 ops\n *\n * Memory Usage Comparison:\n * Window Size | Standard Points | Chunked Points\n * ------------|-----------------|---------------\n * 4-bit | 520 | 15\n * 8-bit | 4,224 | 255\n * 10-bit | 13,824 | 1,023\n * 16-bit | 557,056 | 65,535\n *\n * Key Advantages:\n * 1. Enables larger window sizes due to reduced memory overhead\n * 2. More efficient for smaller scalar counts:\n * - 16 chunks: (16 × 255) + 256 = 4,336 ops\n * - ~2x faster than standard 8,191 ops\n *\n * Limitations:\n * - Not suitable for plain precomputes (requires 256 constant doublings)\n * - Performance degrades with larger scalar counts:\n * - Optimal for ~256 scalars\n * - Less efficient for 4096+ scalars (Pippenger preferred)\n */\n validateW(windowSize, fieldN.BITS);\n validateMSMPoints(points, c);\n const zero = c.ZERO;\n const tableSize = 2 ** windowSize - 1; // table size (without zero)\n const chunks = Math.ceil(fieldN.BITS / windowSize); // chunks of item\n const MASK = BigInt((1 << windowSize) - 1);\n const tables = points.map((p: T) => {\n const res = [];\n for (let i = 0, acc = p; i < tableSize; i++) {\n res.push(acc);\n acc = acc.add(p);\n }\n return res;\n });\n return (scalars: bigint[]): T => {\n validateMSMScalars(scalars, fieldN);\n if (scalars.length > points.length)\n throw new Error('array of scalars must be smaller than array of points');\n let res = zero;\n for (let i = 0; i < chunks; i++) {\n // No need to double if accumulator is still zero.\n if (res !== zero) for (let j = 0; j < windowSize; j++) res = res.double();\n const shiftBy = BigInt(chunks * windowSize - (i + 1) * windowSize);\n for (let j = 0; j < scalars.length; j++) {\n const n = scalars[j];\n const curr = Number((n >> shiftBy) & MASK);\n if (!curr) continue; // skip zero scalars chunks\n res = res.add(tables[j][curr - 1]);\n }\n }\n return res;\n };\n}\n\n/**\n * Generic BasicCurve interface: works even for polynomial fields (BLS): P, n, h would be ok.\n * Though generator can be different (Fp2 / Fp6 for BLS).\n */\nexport type BasicCurve = {\n Fp: IField; // Field over which we'll do calculations (Fp)\n n: bigint; // Curve order, total count of valid points in the field\n nBitLength?: number; // bit length of curve order\n nByteLength?: number; // byte length of curve order\n h: bigint; // cofactor. we can assign default=1, but users will just ignore it w/o validation\n hEff?: bigint; // Number to multiply to clear cofactor\n Gx: T; // base point X coordinate\n Gy: T; // base point Y coordinate\n allowInfinityPoint?: boolean; // bls12-381 requires it. ZERO point is valid, but invalid pubkey\n};\n\nexport function validateBasic(\n curve: BasicCurve & T\n): Readonly<\n {\n readonly nBitLength: number;\n readonly nByteLength: number;\n } & BasicCurve &\n T & {\n p: bigint;\n }\n> {\n validateField(curve.Fp);\n validateObject(\n curve,\n {\n n: 'bigint',\n h: 'bigint',\n Gx: 'field',\n Gy: 'field',\n },\n {\n nBitLength: 'isSafeInteger',\n nByteLength: 'isSafeInteger',\n }\n );\n // Set defaults\n return Object.freeze({\n ...nLength(curve.n, curve.nBitLength),\n ...curve,\n ...{ p: curve.Fp.ORDER },\n } as const);\n}\n","/**\n * Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y².\n * For design rationale of types / exports, see weierstrass module documentation.\n * @module\n */\n/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */\nimport {\n type AffinePoint,\n type BasicCurve,\n type Group,\n type GroupConstructor,\n pippenger,\n validateBasic,\n wNAF,\n} from './curve.js';\nimport { Field, mod } from './modular.js';\nimport * as ut from './utils.js';\nimport { abool, ensureBytes, type FHash, type Hex, memoized } from './utils.js';\n\n// Be friendly to bad ECMAScript parsers by not using bigint literals\n// prettier-ignore\nconst _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _8n = BigInt(8);\n\n/** Edwards curves must declare params a & d. */\nexport type CurveType = BasicCurve & {\n a: bigint; // curve param a\n d: bigint; // curve param d\n hash: FHash; // Hashing\n randomBytes: (bytesLength?: number) => Uint8Array; // CSPRNG\n adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array; // clears bits to get valid field elemtn\n domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; // Used for hashing\n uvRatio?: (u: bigint, v: bigint) => { isValid: boolean; value: bigint }; // Ratio √(u/v)\n prehash?: FHash; // RFC 8032 pre-hashing of messages to sign() / verify()\n mapToCurve?: (scalar: bigint[]) => AffinePoint; // for hash-to-curve standard\n};\n\nexport type CurveTypeWithLength = Readonly;\n\n// verification rule is either zip215 or rfc8032 / nist186-5. Consult fromHex:\nconst VERIFY_DEFAULT = { zip215: true };\n\nfunction validateOpts(curve: CurveType): CurveTypeWithLength {\n const opts = validateBasic(curve);\n ut.validateObject(\n curve,\n {\n hash: 'function',\n a: 'bigint',\n d: 'bigint',\n randomBytes: 'function',\n },\n {\n adjustScalarBytes: 'function',\n domain: 'function',\n uvRatio: 'function',\n mapToCurve: 'function',\n }\n );\n // Set defaults\n return Object.freeze({ ...opts } as const);\n}\n\n/** Instance of Extended Point with coordinates in X, Y, Z, T. */\nexport interface ExtPointType extends Group {\n readonly ex: bigint;\n readonly ey: bigint;\n readonly ez: bigint;\n readonly et: bigint;\n get x(): bigint;\n get y(): bigint;\n assertValidity(): void;\n multiply(scalar: bigint): ExtPointType;\n multiplyUnsafe(scalar: bigint): ExtPointType;\n isSmallOrder(): boolean;\n isTorsionFree(): boolean;\n clearCofactor(): ExtPointType;\n toAffine(iz?: bigint): AffinePoint;\n toRawBytes(isCompressed?: boolean): Uint8Array;\n toHex(isCompressed?: boolean): string;\n _setWindowSize(windowSize: number): void;\n}\n/** Static methods of Extended Point with coordinates in X, Y, Z, T. */\nexport interface ExtPointConstructor extends GroupConstructor {\n new (x: bigint, y: bigint, z: bigint, t: bigint): ExtPointType;\n fromAffine(p: AffinePoint): ExtPointType;\n fromHex(hex: Hex): ExtPointType;\n fromPrivateKey(privateKey: Hex): ExtPointType;\n msm(points: ExtPointType[], scalars: bigint[]): ExtPointType;\n}\n\n/**\n * Edwards Curve interface.\n * Main methods: `getPublicKey(priv)`, `sign(msg, priv)`, `verify(sig, msg, pub)`.\n */\nexport type CurveFn = {\n CURVE: ReturnType;\n getPublicKey: (privateKey: Hex) => Uint8Array;\n sign: (message: Hex, privateKey: Hex, options?: { context?: Hex }) => Uint8Array;\n verify: (\n sig: Hex,\n message: Hex,\n publicKey: Hex,\n options?: { context?: Hex; zip215: boolean }\n ) => boolean;\n ExtendedPoint: ExtPointConstructor;\n utils: {\n randomPrivateKey: () => Uint8Array;\n getExtendedPublicKey: (key: Hex) => {\n head: Uint8Array;\n prefix: Uint8Array;\n scalar: bigint;\n point: ExtPointType;\n pointBytes: Uint8Array;\n };\n precompute: (windowSize?: number, point?: ExtPointType) => ExtPointType;\n };\n};\n\n/**\n * Creates Twisted Edwards curve with EdDSA signatures.\n * @example\n * import { Field } from '@noble/curves/abstract/modular';\n * // Before that, define BigInt-s: a, d, p, n, Gx, Gy, h\n * const curve = twistedEdwards({ a, d, Fp: Field(p), n, Gx, Gy, h })\n */\nexport function twistedEdwards(curveDef: CurveType): CurveFn {\n const CURVE = validateOpts(curveDef) as ReturnType;\n const {\n Fp,\n n: CURVE_ORDER,\n prehash: prehash,\n hash: cHash,\n randomBytes,\n nByteLength,\n h: cofactor,\n } = CURVE;\n // Important:\n // There are some places where Fp.BYTES is used instead of nByteLength.\n // So far, everything has been tested with curves of Fp.BYTES == nByteLength.\n // TODO: test and find curves which behave otherwise.\n const MASK = _2n << (BigInt(nByteLength * 8) - _1n);\n const modP = Fp.create; // Function overrides\n const Fn = Field(CURVE.n, CURVE.nBitLength);\n\n // sqrt(u/v)\n const uvRatio =\n CURVE.uvRatio ||\n ((u: bigint, v: bigint) => {\n try {\n return { isValid: true, value: Fp.sqrt(u * Fp.inv(v)) };\n } catch (e) {\n return { isValid: false, value: _0n };\n }\n });\n const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes: Uint8Array) => bytes); // NOOP\n const domain =\n CURVE.domain ||\n ((data: Uint8Array, ctx: Uint8Array, phflag: boolean) => {\n abool('phflag', phflag);\n if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported');\n return data;\n }); // NOOP\n // 0 <= n < MASK\n // Coordinates larger than Fp.ORDER are allowed for zip215\n function aCoordinate(title: string, n: bigint) {\n ut.aInRange('coordinate ' + title, n, _0n, MASK);\n }\n\n function assertPoint(other: unknown) {\n if (!(other instanceof Point)) throw new Error('ExtendedPoint expected');\n }\n // Converts Extended point to default (x, y) coordinates.\n // Can accept precomputed Z^-1 - for example, from invertBatch.\n const toAffineMemo = memoized((p: Point, iz?: bigint): AffinePoint => {\n const { ex: x, ey: y, ez: z } = p;\n const is0 = p.is0();\n if (iz == null) iz = is0 ? _8n : (Fp.inv(z) as bigint); // 8 was chosen arbitrarily\n const ax = modP(x * iz);\n const ay = modP(y * iz);\n const zz = modP(z * iz);\n if (is0) return { x: _0n, y: _1n };\n if (zz !== _1n) throw new Error('invZ was invalid');\n return { x: ax, y: ay };\n });\n const assertValidMemo = memoized((p: Point) => {\n const { a, d } = CURVE;\n if (p.is0()) throw new Error('bad point: ZERO'); // TODO: optimize, with vars below?\n // Equation in affine coordinates: ax² + y² = 1 + dx²y²\n // Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²\n const { ex: X, ey: Y, ez: Z, et: T } = p;\n const X2 = modP(X * X); // X²\n const Y2 = modP(Y * Y); // Y²\n const Z2 = modP(Z * Z); // Z²\n const Z4 = modP(Z2 * Z2); // Z⁴\n const aX2 = modP(X2 * a); // aX²\n const left = modP(Z2 * modP(aX2 + Y2)); // (aX² + Y²)Z²\n const right = modP(Z4 + modP(d * modP(X2 * Y2))); // Z⁴ + dX²Y²\n if (left !== right) throw new Error('bad point: equation left != right (1)');\n // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T\n const XY = modP(X * Y);\n const ZT = modP(Z * T);\n if (XY !== ZT) throw new Error('bad point: equation left != right (2)');\n return true;\n });\n\n // Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).\n // https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates\n class Point implements ExtPointType {\n static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));\n static readonly ZERO = new Point(_0n, _1n, _1n, _0n); // 0, 1, 1, 0\n\n constructor(\n readonly ex: bigint,\n readonly ey: bigint,\n readonly ez: bigint,\n readonly et: bigint\n ) {\n aCoordinate('x', ex);\n aCoordinate('y', ey);\n aCoordinate('z', ez);\n aCoordinate('t', et);\n Object.freeze(this);\n }\n\n get x(): bigint {\n return this.toAffine().x;\n }\n get y(): bigint {\n return this.toAffine().y;\n }\n\n static fromAffine(p: AffinePoint): Point {\n if (p instanceof Point) throw new Error('extended point not allowed');\n const { x, y } = p || {};\n aCoordinate('x', x);\n aCoordinate('y', y);\n return new Point(x, y, _1n, modP(x * y));\n }\n static normalizeZ(points: Point[]): Point[] {\n const toInv = Fp.invertBatch(points.map((p) => p.ez));\n return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);\n }\n // Multiscalar Multiplication\n static msm(points: Point[], scalars: bigint[]): Point {\n return pippenger(Point, Fn, points, scalars);\n }\n\n // \"Private method\", don't use it directly\n _setWindowSize(windowSize: number) {\n wnaf.setWindowSize(this, windowSize);\n }\n // Not required for fromHex(), which always creates valid points.\n // Could be useful for fromAffine().\n assertValidity(): void {\n assertValidMemo(this);\n }\n\n // Compare one point to another.\n equals(other: Point): boolean {\n assertPoint(other);\n const { ex: X1, ey: Y1, ez: Z1 } = this;\n const { ex: X2, ey: Y2, ez: Z2 } = other;\n const X1Z2 = modP(X1 * Z2);\n const X2Z1 = modP(X2 * Z1);\n const Y1Z2 = modP(Y1 * Z2);\n const Y2Z1 = modP(Y2 * Z1);\n return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;\n }\n\n is0(): boolean {\n return this.equals(Point.ZERO);\n }\n\n negate(): Point {\n // Flips point sign to a negative one (-x, y in affine coords)\n return new Point(modP(-this.ex), this.ey, this.ez, modP(-this.et));\n }\n\n // Fast algo for doubling Extended Point.\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd\n // Cost: 4M + 4S + 1*a + 6add + 1*2.\n double(): Point {\n const { a } = CURVE;\n const { ex: X1, ey: Y1, ez: Z1 } = this;\n const A = modP(X1 * X1); // A = X12\n const B = modP(Y1 * Y1); // B = Y12\n const C = modP(_2n * modP(Z1 * Z1)); // C = 2*Z12\n const D = modP(a * A); // D = a*A\n const x1y1 = X1 + Y1;\n const E = modP(modP(x1y1 * x1y1) - A - B); // E = (X1+Y1)2-A-B\n const G = D + B; // G = D+B\n const F = G - C; // F = G-C\n const H = D - B; // H = D-B\n const X3 = modP(E * F); // X3 = E*F\n const Y3 = modP(G * H); // Y3 = G*H\n const T3 = modP(E * H); // T3 = E*H\n const Z3 = modP(F * G); // Z3 = F*G\n return new Point(X3, Y3, Z3, T3);\n }\n\n // Fast algo for adding 2 Extended Points.\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-add-2008-hwcd\n // Cost: 9M + 1*a + 1*d + 7add.\n add(other: Point) {\n assertPoint(other);\n const { a, d } = CURVE;\n const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;\n const { ex: X2, ey: Y2, ez: Z2, et: T2 } = other;\n // Faster algo for adding 2 Extended Points when curve's a=-1.\n // http://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-4\n // Cost: 8M + 8add + 2*2.\n // Note: It does not check whether the `other` point is valid.\n if (a === BigInt(-1)) {\n const A = modP((Y1 - X1) * (Y2 + X2));\n const B = modP((Y1 + X1) * (Y2 - X2));\n const F = modP(B - A);\n if (F === _0n) return this.double(); // Same point. Tests say it doesn't affect timing\n const C = modP(Z1 * _2n * T2);\n const D = modP(T1 * _2n * Z2);\n const E = D + C;\n const G = B + A;\n const H = D - C;\n const X3 = modP(E * F);\n const Y3 = modP(G * H);\n const T3 = modP(E * H);\n const Z3 = modP(F * G);\n return new Point(X3, Y3, Z3, T3);\n }\n const A = modP(X1 * X2); // A = X1*X2\n const B = modP(Y1 * Y2); // B = Y1*Y2\n const C = modP(T1 * d * T2); // C = T1*d*T2\n const D = modP(Z1 * Z2); // D = Z1*Z2\n const E = modP((X1 + Y1) * (X2 + Y2) - A - B); // E = (X1+Y1)*(X2+Y2)-A-B\n const F = D - C; // F = D-C\n const G = D + C; // G = D+C\n const H = modP(B - a * A); // H = B-a*A\n const X3 = modP(E * F); // X3 = E*F\n const Y3 = modP(G * H); // Y3 = G*H\n const T3 = modP(E * H); // T3 = E*H\n const Z3 = modP(F * G); // Z3 = F*G\n\n return new Point(X3, Y3, Z3, T3);\n }\n\n subtract(other: Point): Point {\n return this.add(other.negate());\n }\n\n private wNAF(n: bigint): { p: Point; f: Point } {\n return wnaf.wNAFCached(this, n, Point.normalizeZ);\n }\n\n // Constant-time multiplication.\n multiply(scalar: bigint): Point {\n const n = scalar;\n ut.aInRange('scalar', n, _1n, CURVE_ORDER); // 1 <= scalar < L\n const { p, f } = this.wNAF(n);\n return Point.normalizeZ([p, f])[0];\n }\n\n // Non-constant-time multiplication. Uses double-and-add algorithm.\n // It's faster, but should only be used when you don't care about\n // an exposed private key e.g. sig verification.\n // Does NOT allow scalars higher than CURVE.n.\n // Accepts optional accumulator to merge with multiply (important for sparse scalars)\n multiplyUnsafe(scalar: bigint, acc = Point.ZERO): Point {\n const n = scalar;\n ut.aInRange('scalar', n, _0n, CURVE_ORDER); // 0 <= scalar < L\n if (n === _0n) return I;\n if (this.is0() || n === _1n) return this;\n return wnaf.wNAFCachedUnsafe(this, n, Point.normalizeZ, acc);\n }\n\n // Checks if point is of small order.\n // If you add something to small order point, you will have \"dirty\"\n // point with torsion component.\n // Multiplies point by cofactor and checks if the result is 0.\n isSmallOrder(): boolean {\n return this.multiplyUnsafe(cofactor).is0();\n }\n\n // Multiplies point by curve order and checks if the result is 0.\n // Returns `false` is the point is dirty.\n isTorsionFree(): boolean {\n return wnaf.unsafeLadder(this, CURVE_ORDER).is0();\n }\n\n // Converts Extended point to default (x, y) coordinates.\n // Can accept precomputed Z^-1 - for example, from invertBatch.\n toAffine(iz?: bigint): AffinePoint {\n return toAffineMemo(this, iz);\n }\n\n clearCofactor(): Point {\n const { h: cofactor } = CURVE;\n if (cofactor === _1n) return this;\n return this.multiplyUnsafe(cofactor);\n }\n\n // Converts hash string or Uint8Array to Point.\n // Uses algo from RFC8032 5.1.3.\n static fromHex(hex: Hex, zip215 = false): Point {\n const { d, a } = CURVE;\n const len = Fp.BYTES;\n hex = ensureBytes('pointHex', hex, len); // copy hex to a new array\n abool('zip215', zip215);\n const normed = hex.slice(); // copy again, we'll manipulate it\n const lastByte = hex[len - 1]; // select last byte\n normed[len - 1] = lastByte & ~0x80; // clear last bit\n const y = ut.bytesToNumberLE(normed);\n\n // zip215=true is good for consensus-critical apps. =false follows RFC8032 / NIST186-5.\n // RFC8032 prohibits >= p, but ZIP215 doesn't\n // zip215=true: 0 <= y < MASK (2^256 for ed25519)\n // zip215=false: 0 <= y < P (2^255-19 for ed25519)\n const max = zip215 ? MASK : Fp.ORDER;\n ut.aInRange('pointHex.y', y, _0n, max);\n\n // Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case:\n // ax²+y²=1+dx²y² => y²-1=dx²y²-ax² => y²-1=x²(dy²-a) => x²=(y²-1)/(dy²-a)\n const y2 = modP(y * y); // denominator is always non-0 mod p.\n const u = modP(y2 - _1n); // u = y² - 1\n const v = modP(d * y2 - a); // v = d y² + 1.\n let { isValid, value: x } = uvRatio(u, v); // √(u/v)\n if (!isValid) throw new Error('Point.fromHex: invalid y coordinate');\n const isXOdd = (x & _1n) === _1n; // There are 2 square roots. Use x_0 bit to select proper\n const isLastByteOdd = (lastByte & 0x80) !== 0; // x_0, last bit\n if (!zip215 && x === _0n && isLastByteOdd)\n // if x=0 and x_0 = 1, fail\n throw new Error('Point.fromHex: x=0 and x_0=1');\n if (isLastByteOdd !== isXOdd) x = modP(-x); // if x_0 != x mod 2, set x = p-x\n return Point.fromAffine({ x, y });\n }\n static fromPrivateKey(privKey: Hex) {\n return getExtendedPublicKey(privKey).point;\n }\n toRawBytes(): Uint8Array {\n const { x, y } = this.toAffine();\n const bytes = ut.numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)\n bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y\n return bytes; // and use the last byte to encode sign of x\n }\n toHex(): string {\n return ut.bytesToHex(this.toRawBytes()); // Same as toRawBytes, but returns string.\n }\n }\n const { BASE: G, ZERO: I } = Point;\n const wnaf = wNAF(Point, nByteLength * 8);\n\n function modN(a: bigint) {\n return mod(a, CURVE_ORDER);\n }\n // Little-endian SHA512 with modulo n\n function modN_LE(hash: Uint8Array): bigint {\n return modN(ut.bytesToNumberLE(hash));\n }\n\n /** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */\n function getExtendedPublicKey(key: Hex) {\n const len = Fp.BYTES;\n key = ensureBytes('private key', key, len);\n // Hash private key with curve's hash function to produce uniformingly random input\n // Check byte lengths: ensure(64, h(ensure(32, key)))\n const hashed = ensureBytes('hashed private key', cHash(key), 2 * len);\n const head = adjustScalarBytes(hashed.slice(0, len)); // clear first half bits, produce FE\n const prefix = hashed.slice(len, 2 * len); // second half is called key prefix (5.1.6)\n const scalar = modN_LE(head); // The actual private scalar\n const point = G.multiply(scalar); // Point on Edwards curve aka public key\n const pointBytes = point.toRawBytes(); // Uint8Array representation\n return { head, prefix, scalar, point, pointBytes };\n }\n\n // Calculates EdDSA pub key. RFC8032 5.1.5. Privkey is hashed. Use first half with 3 bits cleared\n function getPublicKey(privKey: Hex): Uint8Array {\n return getExtendedPublicKey(privKey).pointBytes;\n }\n\n // int('LE', SHA512(dom2(F, C) || msgs)) mod N\n function hashDomainToScalar(context: Hex = new Uint8Array(), ...msgs: Uint8Array[]) {\n const msg = ut.concatBytes(...msgs);\n return modN_LE(cHash(domain(msg, ensureBytes('context', context), !!prehash)));\n }\n\n /** Signs message with privateKey. RFC8032 5.1.6 */\n function sign(msg: Hex, privKey: Hex, options: { context?: Hex } = {}): Uint8Array {\n msg = ensureBytes('message', msg);\n if (prehash) msg = prehash(msg); // for ed25519ph etc.\n const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);\n const r = hashDomainToScalar(options.context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)\n const R = G.multiply(r).toRawBytes(); // R = rG\n const k = hashDomainToScalar(options.context, R, pointBytes, msg); // R || A || PH(M)\n const s = modN(r + k * scalar); // S = (r + k * s) mod L\n ut.aInRange('signature.s', s, _0n, CURVE_ORDER); // 0 <= s < l\n const res = ut.concatBytes(R, ut.numberToBytesLE(s, Fp.BYTES));\n return ensureBytes('result', res, Fp.BYTES * 2); // 64-byte signature\n }\n\n const verifyOpts: { context?: Hex; zip215?: boolean } = VERIFY_DEFAULT;\n\n /**\n * Verifies EdDSA signature against message and public key. RFC8032 5.1.7.\n * An extended group equation is checked.\n */\n function verify(sig: Hex, msg: Hex, publicKey: Hex, options = verifyOpts): boolean {\n const { context, zip215 } = options;\n const len = Fp.BYTES; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7.\n sig = ensureBytes('signature', sig, 2 * len); // An extended group equation is checked.\n msg = ensureBytes('message', msg);\n publicKey = ensureBytes('publicKey', publicKey, len);\n if (zip215 !== undefined) abool('zip215', zip215);\n if (prehash) msg = prehash(msg); // for ed25519ph, etc\n\n const s = ut.bytesToNumberLE(sig.slice(len, 2 * len));\n let A, R, SB;\n try {\n // zip215=true is good for consensus-critical apps. =false follows RFC8032 / NIST186-5.\n // zip215=true: 0 <= y < MASK (2^256 for ed25519)\n // zip215=false: 0 <= y < P (2^255-19 for ed25519)\n A = Point.fromHex(publicKey, zip215);\n R = Point.fromHex(sig.slice(0, len), zip215);\n SB = G.multiplyUnsafe(s); // 0 <= s < l is done inside\n } catch (error) {\n return false;\n }\n if (!zip215 && A.isSmallOrder()) return false;\n\n const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);\n const RkA = R.add(A.multiplyUnsafe(k));\n // Extended group equation\n // [8][S]B = [8]R + [8][k]A'\n return RkA.subtract(SB).clearCofactor().equals(Point.ZERO);\n }\n\n G._setWindowSize(8); // Enable precomputes. Slows down first publicKey computation by 20ms.\n\n const utils = {\n getExtendedPublicKey,\n // ed25519 private keys are uniform 32b. No need to check for modulo bias, like in secp256k1.\n randomPrivateKey: (): Uint8Array => randomBytes(Fp.BYTES),\n\n /**\n * We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT\n * values. This slows down first getPublicKey() by milliseconds (see Speed section),\n * but allows to speed-up subsequent getPublicKey() calls up to 20x.\n * @param windowSize 2, 4, 8, 16\n */\n precompute(windowSize = 8, point: ExtPointType = Point.BASE): ExtPointType {\n point._setWindowSize(windowSize);\n point.multiply(BigInt(3));\n return point;\n },\n };\n\n return {\n CURVE,\n getPublicKey,\n sign,\n verify,\n ExtendedPoint: Point,\n utils,\n };\n}\n","/**\n * ed25519 Twisted Edwards curve with following addons:\n * - X25519 ECDH\n * - Ristretto cofactor elimination\n * - Elligator hash-to-group / point indistinguishability\n * @module\n */\n/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */\nimport { sha512 } from '@noble/hashes/sha512';\nimport { concatBytes, randomBytes, utf8ToBytes } from '@noble/hashes/utils';\nimport { type AffinePoint, type Group, pippenger } from './abstract/curve.js';\nimport { type CurveFn, type ExtPointType, twistedEdwards } from './abstract/edwards.js';\nimport {\n createHasher,\n expand_message_xmd,\n type htfBasicOpts,\n type HTFMethod,\n} from './abstract/hash-to-curve.js';\nimport { Field, FpSqrtEven, isNegativeLE, mod, pow2 } from './abstract/modular.js';\nimport { montgomery, type CurveFn as XCurveFn } from './abstract/montgomery.js';\nimport {\n bytesToHex,\n bytesToNumberLE,\n ensureBytes,\n equalBytes,\n type Hex,\n numberToBytesLE,\n} from './abstract/utils.js';\n\nconst ED25519_P = BigInt(\n '57896044618658097711785492504343953926634992332820282019728792003956564819949'\n);\n// √(-1) aka √(a) aka 2^((p-1)/4)\nconst ED25519_SQRT_M1 = /* @__PURE__ */ BigInt(\n '19681161376707505956807079304988542015446066515923890162744021073123829784752'\n);\n\n// prettier-ignore\nconst _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);\n// prettier-ignore\nconst _5n = BigInt(5), _8n = BigInt(8);\n\nfunction ed25519_pow_2_252_3(x: bigint) {\n // prettier-ignore\n const _10n = BigInt(10), _20n = BigInt(20), _40n = BigInt(40), _80n = BigInt(80);\n const P = ED25519_P;\n const x2 = (x * x) % P;\n const b2 = (x2 * x) % P; // x^3, 11\n const b4 = (pow2(b2, _2n, P) * b2) % P; // x^15, 1111\n const b5 = (pow2(b4, _1n, P) * x) % P; // x^31\n const b10 = (pow2(b5, _5n, P) * b5) % P;\n const b20 = (pow2(b10, _10n, P) * b10) % P;\n const b40 = (pow2(b20, _20n, P) * b20) % P;\n const b80 = (pow2(b40, _40n, P) * b40) % P;\n const b160 = (pow2(b80, _80n, P) * b80) % P;\n const b240 = (pow2(b160, _80n, P) * b80) % P;\n const b250 = (pow2(b240, _10n, P) * b10) % P;\n const pow_p_5_8 = (pow2(b250, _2n, P) * x) % P;\n // ^ To pow to (p+3)/8, multiply it by x.\n return { pow_p_5_8, b2 };\n}\n\nfunction adjustScalarBytes(bytes: Uint8Array): Uint8Array {\n // Section 5: For X25519, in order to decode 32 random bytes as an integer scalar,\n // set the three least significant bits of the first byte\n bytes[0] &= 248; // 0b1111_1000\n // and the most significant bit of the last to zero,\n bytes[31] &= 127; // 0b0111_1111\n // set the second most significant bit of the last byte to 1\n bytes[31] |= 64; // 0b0100_0000\n return bytes;\n}\n\n// sqrt(u/v)\nfunction uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {\n const P = ED25519_P;\n const v3 = mod(v * v * v, P); // v³\n const v7 = mod(v3 * v3 * v, P); // v⁷\n // (p+3)/8 and (p-5)/8\n const pow = ed25519_pow_2_252_3(u * v7).pow_p_5_8;\n let x = mod(u * v3 * pow, P); // (uv³)(uv⁷)^(p-5)/8\n const vx2 = mod(v * x * x, P); // vx²\n const root1 = x; // First root candidate\n const root2 = mod(x * ED25519_SQRT_M1, P); // Second root candidate\n const useRoot1 = vx2 === u; // If vx² = u (mod p), x is a square root\n const useRoot2 = vx2 === mod(-u, P); // If vx² = -u, set x <-- x * 2^((p-1)/4)\n const noRoot = vx2 === mod(-u * ED25519_SQRT_M1, P); // There is no valid root, vx² = -u√(-1)\n if (useRoot1) x = root1;\n if (useRoot2 || noRoot) x = root2; // We return root2 anyway, for const-time\n if (isNegativeLE(x, P)) x = mod(-x, P);\n return { isValid: useRoot1 || useRoot2, value: x };\n}\n\n// Just in case\nexport const ED25519_TORSION_SUBGROUP: string[] = [\n '0100000000000000000000000000000000000000000000000000000000000000',\n 'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a',\n '0000000000000000000000000000000000000000000000000000000000000080',\n '26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05',\n 'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',\n '26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85',\n '0000000000000000000000000000000000000000000000000000000000000000',\n 'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa',\n];\n\nconst Fp = /* @__PURE__ */ (() => Field(ED25519_P, undefined, true))();\n\nconst ed25519Defaults = /* @__PURE__ */ (() =>\n ({\n // Param: a\n a: BigInt(-1), // Fp.create(-1) is proper; our way still works and is faster\n // d is equal to -121665/121666 over finite field.\n // Negative number is P - number, and division is invert(number, P)\n d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),\n // Finite field 𝔽p over which we'll do calculations; 2n**255n - 19n\n Fp,\n // Subgroup order: how many points curve has\n // 2n**252n + 27742317777372353535851937790883648493n;\n n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),\n // Cofactor\n h: _8n,\n // Base point (x, y) aka generator point\n Gx: BigInt('15112221349535400772501151409588531511454012693041857206046113283949847762202'),\n Gy: BigInt('46316835694926478169428394003475163141307993866256225615783033603165251855960'),\n hash: sha512,\n randomBytes,\n adjustScalarBytes,\n // dom2\n // Ratio of u to v. Allows us to combine inversion and square root. Uses algo from RFC8032 5.1.3.\n // Constant-time, u/√v\n uvRatio,\n }) as const)();\n\n/**\n * ed25519 curve with EdDSA signatures.\n * @example\n * import { ed25519 } from '@noble/curves/ed25519';\n * const priv = ed25519.utils.randomPrivateKey();\n * const pub = ed25519.getPublicKey(priv);\n * const msg = new TextEncoder().encode('hello');\n * const sig = ed25519.sign(msg, priv);\n * ed25519.verify(sig, msg, pub); // Default mode: follows ZIP215\n * ed25519.verify(sig, msg, pub, { zip215: false }); // RFC8032 / FIPS 186-5\n */\nexport const ed25519: CurveFn = /* @__PURE__ */ (() => twistedEdwards(ed25519Defaults))();\n\nfunction ed25519_domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {\n if (ctx.length > 255) throw new Error('Context is too big');\n return concatBytes(\n utf8ToBytes('SigEd25519 no Ed25519 collisions'),\n new Uint8Array([phflag ? 1 : 0, ctx.length]),\n ctx,\n data\n );\n}\n\nexport const ed25519ctx: CurveFn = /* @__PURE__ */ (() =>\n twistedEdwards({\n ...ed25519Defaults,\n domain: ed25519_domain,\n }))();\nexport const ed25519ph: CurveFn = /* @__PURE__ */ (() =>\n twistedEdwards(\n Object.assign({}, ed25519Defaults, {\n domain: ed25519_domain,\n prehash: sha512,\n })\n ))();\n\n/**\n * ECDH using curve25519 aka x25519.\n * @example\n * import { x25519 } from '@noble/curves/ed25519';\n * const priv = 'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4';\n * const pub = 'e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c';\n * x25519.getSharedSecret(priv, pub) === x25519.scalarMult(priv, pub); // aliases\n * x25519.getPublicKey(priv) === x25519.scalarMultBase(priv);\n * x25519.getPublicKey(x25519.utils.randomPrivateKey());\n */\nexport const x25519: XCurveFn = /* @__PURE__ */ (() =>\n montgomery({\n P: ED25519_P,\n a: BigInt(486662),\n montgomeryBits: 255, // n is 253 bits\n nByteLength: 32,\n Gu: BigInt(9),\n powPminus2: (x: bigint): bigint => {\n const P = ED25519_P;\n // x^(p-2) aka x^(2^255-21)\n const { pow_p_5_8, b2 } = ed25519_pow_2_252_3(x);\n return mod(pow2(pow_p_5_8, _3n, P) * b2, P);\n },\n adjustScalarBytes,\n randomBytes,\n }))();\n\n/**\n * Converts ed25519 public key to x25519 public key. Uses formula:\n * * `(u, v) = ((1+y)/(1-y), sqrt(-486664)*u/x)`\n * * `(x, y) = (sqrt(-486664)*u/v, (u-1)/(u+1))`\n * @example\n * const someonesPub = ed25519.getPublicKey(ed25519.utils.randomPrivateKey());\n * const aPriv = x25519.utils.randomPrivateKey();\n * x25519.getSharedSecret(aPriv, edwardsToMontgomeryPub(someonesPub))\n */\nexport function edwardsToMontgomeryPub(edwardsPub: Hex): Uint8Array {\n const { y } = ed25519.ExtendedPoint.fromHex(edwardsPub);\n const _1n = BigInt(1);\n return Fp.toBytes(Fp.create((_1n + y) * Fp.inv(_1n - y)));\n}\nexport const edwardsToMontgomery: typeof edwardsToMontgomeryPub = edwardsToMontgomeryPub; // deprecated\n\n/**\n * Converts ed25519 secret key to x25519 secret key.\n * @example\n * const someonesPub = x25519.getPublicKey(x25519.utils.randomPrivateKey());\n * const aPriv = ed25519.utils.randomPrivateKey();\n * x25519.getSharedSecret(edwardsToMontgomeryPriv(aPriv), someonesPub)\n */\nexport function edwardsToMontgomeryPriv(edwardsPriv: Uint8Array): Uint8Array {\n const hashed = ed25519Defaults.hash(edwardsPriv.subarray(0, 32));\n return ed25519Defaults.adjustScalarBytes(hashed).subarray(0, 32);\n}\n\n// Hash To Curve Elligator2 Map (NOTE: different from ristretto255 elligator)\n// NOTE: very important part is usage of FpSqrtEven for ELL2_C1_EDWARDS, since\n// SageMath returns different root first and everything falls apart\n\nconst ELL2_C1 = /* @__PURE__ */ (() => (Fp.ORDER + _3n) / _8n)(); // 1. c1 = (q + 3) / 8 # Integer arithmetic\nconst ELL2_C2 = /* @__PURE__ */ (() => Fp.pow(_2n, ELL2_C1))(); // 2. c2 = 2^c1\nconst ELL2_C3 = /* @__PURE__ */ (() => Fp.sqrt(Fp.neg(Fp.ONE)))(); // 3. c3 = sqrt(-1)\n\n// prettier-ignore\nfunction map_to_curve_elligator2_curve25519(u: bigint) {\n const ELL2_C4 = (Fp.ORDER - _5n) / _8n; // 4. c4 = (q - 5) / 8 # Integer arithmetic\n const ELL2_J = BigInt(486662);\n\n let tv1 = Fp.sqr(u); // 1. tv1 = u^2\n tv1 = Fp.mul(tv1, _2n); // 2. tv1 = 2 * tv1\n let xd = Fp.add(tv1, Fp.ONE); // 3. xd = tv1 + 1 # Nonzero: -1 is square (mod p), tv1 is not\n let x1n = Fp.neg(ELL2_J); // 4. x1n = -J # x1 = x1n / xd = -J / (1 + 2 * u^2)\n let tv2 = Fp.sqr(xd); // 5. tv2 = xd^2\n let gxd = Fp.mul(tv2, xd); // 6. gxd = tv2 * xd # gxd = xd^3\n let gx1 = Fp.mul(tv1, ELL2_J);// 7. gx1 = J * tv1 # x1n + J * xd\n gx1 = Fp.mul(gx1, x1n); // 8. gx1 = gx1 * x1n # x1n^2 + J * x1n * xd\n gx1 = Fp.add(gx1, tv2); // 9. gx1 = gx1 + tv2 # x1n^2 + J * x1n * xd + xd^2\n gx1 = Fp.mul(gx1, x1n); // 10. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2\n let tv3 = Fp.sqr(gxd); // 11. tv3 = gxd^2\n tv2 = Fp.sqr(tv3); // 12. tv2 = tv3^2 # gxd^4\n tv3 = Fp.mul(tv3, gxd); // 13. tv3 = tv3 * gxd # gxd^3\n tv3 = Fp.mul(tv3, gx1); // 14. tv3 = tv3 * gx1 # gx1 * gxd^3\n tv2 = Fp.mul(tv2, tv3); // 15. tv2 = tv2 * tv3 # gx1 * gxd^7\n let y11 = Fp.pow(tv2, ELL2_C4); // 16. y11 = tv2^c4 # (gx1 * gxd^7)^((p - 5) / 8)\n y11 = Fp.mul(y11, tv3); // 17. y11 = y11 * tv3 # gx1*gxd^3*(gx1*gxd^7)^((p-5)/8)\n let y12 = Fp.mul(y11, ELL2_C3); // 18. y12 = y11 * c3\n tv2 = Fp.sqr(y11); // 19. tv2 = y11^2\n tv2 = Fp.mul(tv2, gxd); // 20. tv2 = tv2 * gxd\n let e1 = Fp.eql(tv2, gx1); // 21. e1 = tv2 == gx1\n let y1 = Fp.cmov(y12, y11, e1); // 22. y1 = CMOV(y12, y11, e1) # If g(x1) is square, this is its sqrt\n let x2n = Fp.mul(x1n, tv1); // 23. x2n = x1n * tv1 # x2 = x2n / xd = 2 * u^2 * x1n / xd\n let y21 = Fp.mul(y11, u); // 24. y21 = y11 * u\n y21 = Fp.mul(y21, ELL2_C2); // 25. y21 = y21 * c2\n let y22 = Fp.mul(y21, ELL2_C3); // 26. y22 = y21 * c3\n let gx2 = Fp.mul(gx1, tv1); // 27. gx2 = gx1 * tv1 # g(x2) = gx2 / gxd = 2 * u^2 * g(x1)\n tv2 = Fp.sqr(y21); // 28. tv2 = y21^2\n tv2 = Fp.mul(tv2, gxd); // 29. tv2 = tv2 * gxd\n let e2 = Fp.eql(tv2, gx2); // 30. e2 = tv2 == gx2\n let y2 = Fp.cmov(y22, y21, e2); // 31. y2 = CMOV(y22, y21, e2) # If g(x2) is square, this is its sqrt\n tv2 = Fp.sqr(y1); // 32. tv2 = y1^2\n tv2 = Fp.mul(tv2, gxd); // 33. tv2 = tv2 * gxd\n let e3 = Fp.eql(tv2, gx1); // 34. e3 = tv2 == gx1\n let xn = Fp.cmov(x2n, x1n, e3); // 35. xn = CMOV(x2n, x1n, e3) # If e3, x = x1, else x = x2\n let y = Fp.cmov(y2, y1, e3); // 36. y = CMOV(y2, y1, e3) # If e3, y = y1, else y = y2\n let e4 = Fp.isOdd(y); // 37. e4 = sgn0(y) == 1 # Fix sign of y\n y = Fp.cmov(y, Fp.neg(y), e3 !== e4); // 38. y = CMOV(y, -y, e3 XOR e4)\n return { xMn: xn, xMd: xd, yMn: y, yMd: _1n }; // 39. return (xn, xd, y, 1)\n}\n\nconst ELL2_C1_EDWARDS = /* @__PURE__ */ (() => FpSqrtEven(Fp, Fp.neg(BigInt(486664))))(); // sgn0(c1) MUST equal 0\nfunction map_to_curve_elligator2_edwards25519(u: bigint) {\n const { xMn, xMd, yMn, yMd } = map_to_curve_elligator2_curve25519(u); // 1. (xMn, xMd, yMn, yMd) =\n // map_to_curve_elligator2_curve25519(u)\n let xn = Fp.mul(xMn, yMd); // 2. xn = xMn * yMd\n xn = Fp.mul(xn, ELL2_C1_EDWARDS); // 3. xn = xn * c1\n let xd = Fp.mul(xMd, yMn); // 4. xd = xMd * yMn # xn / xd = c1 * xM / yM\n let yn = Fp.sub(xMn, xMd); // 5. yn = xMn - xMd\n let yd = Fp.add(xMn, xMd); // 6. yd = xMn + xMd # (n / d - 1) / (n / d + 1) = (n - d) / (n + d)\n let tv1 = Fp.mul(xd, yd); // 7. tv1 = xd * yd\n let e = Fp.eql(tv1, Fp.ZERO); // 8. e = tv1 == 0\n xn = Fp.cmov(xn, Fp.ZERO, e); // 9. xn = CMOV(xn, 0, e)\n xd = Fp.cmov(xd, Fp.ONE, e); // 10. xd = CMOV(xd, 1, e)\n yn = Fp.cmov(yn, Fp.ONE, e); // 11. yn = CMOV(yn, 1, e)\n yd = Fp.cmov(yd, Fp.ONE, e); // 12. yd = CMOV(yd, 1, e)\n\n const inv = Fp.invertBatch([xd, yd]); // batch division\n return { x: Fp.mul(xn, inv[0]), y: Fp.mul(yn, inv[1]) }; // 13. return (xn, xd, yn, yd)\n}\n\nconst htf = /* @__PURE__ */ (() =>\n createHasher(\n ed25519.ExtendedPoint,\n (scalars: bigint[]) => map_to_curve_elligator2_edwards25519(scalars[0]),\n {\n DST: 'edwards25519_XMD:SHA-512_ELL2_RO_',\n encodeDST: 'edwards25519_XMD:SHA-512_ELL2_NU_',\n p: Fp.ORDER,\n m: 1,\n k: 128,\n expand: 'xmd',\n hash: sha512,\n }\n ))();\nexport const hashToCurve: HTFMethod = /* @__PURE__ */ (() => htf.hashToCurve)();\nexport const encodeToCurve: HTFMethod = /* @__PURE__ */ (() => htf.encodeToCurve)();\n\nfunction assertRstPoint(other: unknown) {\n if (!(other instanceof RistPoint)) throw new Error('RistrettoPoint expected');\n}\n\n// √(-1) aka √(a) aka 2^((p-1)/4)\nconst SQRT_M1 = ED25519_SQRT_M1;\n// √(ad - 1)\nconst SQRT_AD_MINUS_ONE = /* @__PURE__ */ BigInt(\n '25063068953384623474111414158702152701244531502492656460079210482610430750235'\n);\n// 1 / √(a-d)\nconst INVSQRT_A_MINUS_D = /* @__PURE__ */ BigInt(\n '54469307008909316920995813868745141605393597292927456921205312896311721017578'\n);\n// 1-d²\nconst ONE_MINUS_D_SQ = /* @__PURE__ */ BigInt(\n '1159843021668779879193775521855586647937357759715417654439879720876111806838'\n);\n// (d-1)²\nconst D_MINUS_ONE_SQ = /* @__PURE__ */ BigInt(\n '40440834346308536858101042469323190826248399146238708352240133220865137265952'\n);\n// Calculates 1/√(number)\nconst invertSqrt = (number: bigint) => uvRatio(_1n, number);\n\nconst MAX_255B = /* @__PURE__ */ BigInt(\n '0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'\n);\nconst bytes255ToNumberLE = (bytes: Uint8Array) =>\n ed25519.CURVE.Fp.create(bytesToNumberLE(bytes) & MAX_255B);\n\ntype ExtendedPoint = ExtPointType;\n\n// Computes Elligator map for Ristretto\n// https://ristretto.group/formulas/elligator.html\nfunction calcElligatorRistrettoMap(r0: bigint): ExtendedPoint {\n const { d } = ed25519.CURVE;\n const P = ed25519.CURVE.Fp.ORDER;\n const mod = ed25519.CURVE.Fp.create;\n const r = mod(SQRT_M1 * r0 * r0); // 1\n const Ns = mod((r + _1n) * ONE_MINUS_D_SQ); // 2\n let c = BigInt(-1); // 3\n const D = mod((c - d * r) * mod(r + d)); // 4\n let { isValid: Ns_D_is_sq, value: s } = uvRatio(Ns, D); // 5\n let s_ = mod(s * r0); // 6\n if (!isNegativeLE(s_, P)) s_ = mod(-s_);\n if (!Ns_D_is_sq) s = s_; // 7\n if (!Ns_D_is_sq) c = r; // 8\n const Nt = mod(c * (r - _1n) * D_MINUS_ONE_SQ - D); // 9\n const s2 = s * s;\n const W0 = mod((s + s) * D); // 10\n const W1 = mod(Nt * SQRT_AD_MINUS_ONE); // 11\n const W2 = mod(_1n - s2); // 12\n const W3 = mod(_1n + s2); // 13\n return new ed25519.ExtendedPoint(mod(W0 * W3), mod(W2 * W1), mod(W1 * W3), mod(W0 * W2));\n}\n\n/**\n * Each ed25519/ExtendedPoint has 8 different equivalent points. This can be\n * a source of bugs for protocols like ring signatures. Ristretto was created to solve this.\n * Ristretto point operates in X:Y:Z:T extended coordinates like ExtendedPoint,\n * but it should work in its own namespace: do not combine those two.\n * https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448\n */\nclass RistPoint implements Group {\n static BASE: RistPoint;\n static ZERO: RistPoint;\n // Private property to discourage combining ExtendedPoint + RistrettoPoint\n // Always use Ristretto encoding/decoding instead.\n constructor(private readonly ep: ExtendedPoint) {}\n\n static fromAffine(ap: AffinePoint): RistPoint {\n return new RistPoint(ed25519.ExtendedPoint.fromAffine(ap));\n }\n\n /**\n * Takes uniform output of 64-byte hash function like sha512 and converts it to `RistrettoPoint`.\n * The hash-to-group operation applies Elligator twice and adds the results.\n * **Note:** this is one-way map, there is no conversion from point to hash.\n * https://ristretto.group/formulas/elligator.html\n * @param hex 64-byte output of a hash function\n */\n static hashToCurve(hex: Hex): RistPoint {\n hex = ensureBytes('ristrettoHash', hex, 64);\n const r1 = bytes255ToNumberLE(hex.slice(0, 32));\n const R1 = calcElligatorRistrettoMap(r1);\n const r2 = bytes255ToNumberLE(hex.slice(32, 64));\n const R2 = calcElligatorRistrettoMap(r2);\n return new RistPoint(R1.add(R2));\n }\n\n /**\n * Converts ristretto-encoded string to ristretto point.\n * https://ristretto.group/formulas/decoding.html\n * @param hex Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding\n */\n static fromHex(hex: Hex): RistPoint {\n hex = ensureBytes('ristrettoHex', hex, 32);\n const { a, d } = ed25519.CURVE;\n const P = ed25519.CURVE.Fp.ORDER;\n const mod = ed25519.CURVE.Fp.create;\n const emsg = 'RistrettoPoint.fromHex: the hex is not valid encoding of RistrettoPoint';\n const s = bytes255ToNumberLE(hex);\n // 1. Check that s_bytes is the canonical encoding of a field element, or else abort.\n // 3. Check that s is non-negative, or else abort\n if (!equalBytes(numberToBytesLE(s, 32), hex) || isNegativeLE(s, P)) throw new Error(emsg);\n const s2 = mod(s * s);\n const u1 = mod(_1n + a * s2); // 4 (a is -1)\n const u2 = mod(_1n - a * s2); // 5\n const u1_2 = mod(u1 * u1);\n const u2_2 = mod(u2 * u2);\n const v = mod(a * d * u1_2 - u2_2); // 6\n const { isValid, value: I } = invertSqrt(mod(v * u2_2)); // 7\n const Dx = mod(I * u2); // 8\n const Dy = mod(I * Dx * v); // 9\n let x = mod((s + s) * Dx); // 10\n if (isNegativeLE(x, P)) x = mod(-x); // 10\n const y = mod(u1 * Dy); // 11\n const t = mod(x * y); // 12\n if (!isValid || isNegativeLE(t, P) || y === _0n) throw new Error(emsg);\n return new RistPoint(new ed25519.ExtendedPoint(x, y, _1n, t));\n }\n\n static msm(points: RistPoint[], scalars: bigint[]): RistPoint {\n const Fn = Field(ed25519.CURVE.n, ed25519.CURVE.nBitLength);\n return pippenger(RistPoint, Fn, points, scalars);\n }\n\n /**\n * Encodes ristretto point to Uint8Array.\n * https://ristretto.group/formulas/encoding.html\n */\n toRawBytes(): Uint8Array {\n let { ex: x, ey: y, ez: z, et: t } = this.ep;\n const P = ed25519.CURVE.Fp.ORDER;\n const mod = ed25519.CURVE.Fp.create;\n const u1 = mod(mod(z + y) * mod(z - y)); // 1\n const u2 = mod(x * y); // 2\n // Square root always exists\n const u2sq = mod(u2 * u2);\n const { value: invsqrt } = invertSqrt(mod(u1 * u2sq)); // 3\n const D1 = mod(invsqrt * u1); // 4\n const D2 = mod(invsqrt * u2); // 5\n const zInv = mod(D1 * D2 * t); // 6\n let D: bigint; // 7\n if (isNegativeLE(t * zInv, P)) {\n let _x = mod(y * SQRT_M1);\n let _y = mod(x * SQRT_M1);\n x = _x;\n y = _y;\n D = mod(D1 * INVSQRT_A_MINUS_D);\n } else {\n D = D2; // 8\n }\n if (isNegativeLE(x * zInv, P)) y = mod(-y); // 9\n let s = mod((z - y) * D); // 10 (check footer's note, no sqrt(-a))\n if (isNegativeLE(s, P)) s = mod(-s);\n return numberToBytesLE(s, 32); // 11\n }\n\n toHex(): string {\n return bytesToHex(this.toRawBytes());\n }\n\n toString(): string {\n return this.toHex();\n }\n\n // Compare one point to another.\n equals(other: RistPoint): boolean {\n assertRstPoint(other);\n const { ex: X1, ey: Y1 } = this.ep;\n const { ex: X2, ey: Y2 } = other.ep;\n const mod = ed25519.CURVE.Fp.create;\n // (x1 * y2 == y1 * x2) | (y1 * y2 == x1 * x2)\n const one = mod(X1 * Y2) === mod(Y1 * X2);\n const two = mod(Y1 * Y2) === mod(X1 * X2);\n return one || two;\n }\n\n add(other: RistPoint): RistPoint {\n assertRstPoint(other);\n return new RistPoint(this.ep.add(other.ep));\n }\n\n subtract(other: RistPoint): RistPoint {\n assertRstPoint(other);\n return new RistPoint(this.ep.subtract(other.ep));\n }\n\n multiply(scalar: bigint): RistPoint {\n return new RistPoint(this.ep.multiply(scalar));\n }\n\n multiplyUnsafe(scalar: bigint): RistPoint {\n return new RistPoint(this.ep.multiplyUnsafe(scalar));\n }\n\n double(): RistPoint {\n return new RistPoint(this.ep.double());\n }\n\n negate(): RistPoint {\n return new RistPoint(this.ep.negate());\n }\n}\nexport const RistrettoPoint: typeof RistPoint = /* @__PURE__ */ (() => {\n if (!RistPoint.BASE) RistPoint.BASE = new RistPoint(ed25519.ExtendedPoint.BASE);\n if (!RistPoint.ZERO) RistPoint.ZERO = new RistPoint(ed25519.ExtendedPoint.ZERO);\n return RistPoint;\n})();\n\n// Hashing to ristretto255. https://www.rfc-editor.org/rfc/rfc9380#appendix-B\nexport const hashToRistretto255 = (msg: Uint8Array, options: htfBasicOpts): RistPoint => {\n const d = options.DST;\n const DST = typeof d === 'string' ? utf8ToBytes(d) : d;\n const uniform_bytes = expand_message_xmd(msg, DST, 64, sha512);\n const P = RistPoint.hashToCurve(uniform_bytes);\n return P;\n};\nexport const hash_to_ristretto255: (msg: Uint8Array, options: htfBasicOpts) => RistPoint =\n hashToRistretto255; // legacy\n","/**\n * SHA2-256 a.k.a. sha256. In JS, it is the fastest hash, even faster than Blake3.\n *\n * To break sha256 using birthday attack, attackers need to try 2^128 hashes.\n * BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.\n *\n * Check out [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).\n * @module\n */\nimport { Chi, HashMD, Maj } from './_md.js';\nimport { type CHash, rotr, wrapConstructor } from './utils.js';\n\n/** Round constants: first 32 bits of fractional parts of the cube roots of the first 64 primes 2..311). */\n// prettier-ignore\nconst SHA256_K = /* @__PURE__ */ new Uint32Array([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\n]);\n\n/** Initial state: first 32 bits of fractional parts of the square roots of the first 8 primes 2..19. */\n// prettier-ignore\nconst SHA256_IV = /* @__PURE__ */ new Uint32Array([\n 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19\n]);\n\n/**\n * Temporary buffer, not used to store anything between runs.\n * Named this way because it matches specification.\n */\nconst SHA256_W = /* @__PURE__ */ new Uint32Array(64);\nexport class SHA256 extends HashMD {\n // We cannot use array here since array allows indexing by variable\n // which means optimizer/compiler cannot use registers.\n protected A: number = SHA256_IV[0] | 0;\n protected B: number = SHA256_IV[1] | 0;\n protected C: number = SHA256_IV[2] | 0;\n protected D: number = SHA256_IV[3] | 0;\n protected E: number = SHA256_IV[4] | 0;\n protected F: number = SHA256_IV[5] | 0;\n protected G: number = SHA256_IV[6] | 0;\n protected H: number = SHA256_IV[7] | 0;\n\n constructor() {\n super(64, 32, 8, false);\n }\n protected get(): [number, number, number, number, number, number, number, number] {\n const { A, B, C, D, E, F, G, H } = this;\n return [A, B, C, D, E, F, G, H];\n }\n // prettier-ignore\n protected set(\n A: number, B: number, C: number, D: number, E: number, F: number, G: number, H: number\n ): void {\n this.A = A | 0;\n this.B = B | 0;\n this.C = C | 0;\n this.D = D | 0;\n this.E = E | 0;\n this.F = F | 0;\n this.G = G | 0;\n this.H = H | 0;\n }\n protected process(view: DataView, offset: number): void {\n // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array\n for (let i = 0; i < 16; i++, offset += 4) SHA256_W[i] = view.getUint32(offset, false);\n for (let i = 16; i < 64; i++) {\n const W15 = SHA256_W[i - 15];\n const W2 = SHA256_W[i - 2];\n const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);\n const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);\n SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;\n }\n // Compression function main loop, 64 rounds\n let { A, B, C, D, E, F, G, H } = this;\n for (let i = 0; i < 64; i++) {\n const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);\n const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;\n const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);\n const T2 = (sigma0 + Maj(A, B, C)) | 0;\n H = G;\n G = F;\n F = E;\n E = (D + T1) | 0;\n D = C;\n C = B;\n B = A;\n A = (T1 + T2) | 0;\n }\n // Add the compressed chunk to the current hash value\n A = (A + this.A) | 0;\n B = (B + this.B) | 0;\n C = (C + this.C) | 0;\n D = (D + this.D) | 0;\n E = (E + this.E) | 0;\n F = (F + this.F) | 0;\n G = (G + this.G) | 0;\n H = (H + this.H) | 0;\n this.set(A, B, C, D, E, F, G, H);\n }\n protected roundClean(): void {\n SHA256_W.fill(0);\n }\n destroy(): void {\n this.set(0, 0, 0, 0, 0, 0, 0, 0);\n this.buffer.fill(0);\n }\n}\n\n/**\n * Constants taken from https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf.\n */\nclass SHA224 extends SHA256 {\n protected A = 0xc1059ed8 | 0;\n protected B = 0x367cd507 | 0;\n protected C = 0x3070dd17 | 0;\n protected D = 0xf70e5939 | 0;\n protected E = 0xffc00b31 | 0;\n protected F = 0x68581511 | 0;\n protected G = 0x64f98fa7 | 0;\n protected H = 0xbefa4fa4 | 0;\n constructor() {\n super();\n this.outputLen = 28;\n }\n}\n\n/** SHA2-256 hash function */\nexport const sha256: CHash = /* @__PURE__ */ wrapConstructor(() => new SHA256());\n/** SHA2-224 hash function */\nexport const sha224: CHash = /* @__PURE__ */ wrapConstructor(() => new SHA224());\n","// @ts-check\n\n/**\n * Base58 characters include numbers 123456789, uppercase ABCDEFGHJKLMNPQRSTUVWXYZ and lowercase abcdefghijkmnopqrstuvwxyz.\n * @typedef {String} base58_chars Base58 characters include numbers 123456789, uppercase ABCDEFGHJKLMNPQRSTUVWXYZ and lowercase abcdefghijkmnopqrstuvwxyz.\n */\nconst base58_chars =\n \"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\n\nexport default base58_chars;\n","import base58_chars from \"./base58_chars.js\";\n\n/**\n * Converts a base58 string to the corresponding binary representation.\n * @param { import(\"./base58_chars.js\").base58_chars } base58String base58 encoded string.\n * @returns {Uint8Array} Binary representation for the base58 string.\n * @example\n * ```js\n * const bin = base58_to_binary(\"6MRy\")\n * console.log(bin)\n * ```\n * Logged output will be Uint8Array(3) [15, 239, 64].\n */\nfunction base58_to_binary(base58String) {\n if (!base58String || typeof base58String !== \"string\")\n throw new Error(`Expected base58 string but got “${base58String}”`);\n if (base58String.match(/[IOl0]/gmu))\n throw new Error(\n `Invalid base58 character “${base58String.match(/[IOl0]/gmu)}”`\n );\n const lz = base58String.match(/^1+/gmu);\n const psz = lz ? lz[0].length : 0;\n const size =\n ((base58String.length - psz) * (Math.log(58) / Math.log(256)) + 1) >>> 0;\n\n return new Uint8Array([\n ...new Uint8Array(psz),\n ...base58String\n .match(/.{1}/gmu)\n .map((i) => base58_chars.indexOf(i))\n .reduce((acc, i) => {\n acc = acc.map((j) => {\n const x = j * 58 + i;\n i = x >> 8;\n return x;\n });\n return acc;\n }, new Uint8Array(size))\n .reverse()\n .filter(\n (\n (lastValue) => (value) =>\n // @ts-ignore\n (lastValue = lastValue || value)\n )(false)\n ),\n ]);\n}\n\nexport default base58_to_binary;\n","// @ts-check\n\nimport base58_chars from \"./base58_chars.js\";\n\n/**\n * Generates a mapping between base58 and ascii.\n * @returns {Array} mapping between ascii and base58.\n */\nconst create_base58_map = () => {\n const base58M = Array(256).fill(-1);\n for (let i = 0; i < base58_chars.length; ++i)\n base58M[base58_chars.charCodeAt(i)] = i;\n\n return base58M;\n};\n\nexport default create_base58_map;\n","// @ts-check\n\nimport base58_chars from \"./base58_chars.js\";\nimport create_base58_map from \"./create_base58_map.js\";\n\nconst base58Map = create_base58_map();\n\n/** @typedef {import(\"./base58_chars.js\").base58_chars} base58_chars */\n\n/**\n * Converts a Uint8Array into a base58 string.\n * @param {Uint8Array} uint8array Unsigned integer array.\n * @returns { import(\"./base58_chars.js\").base58_chars } base58 string representation of the binary array.\n * @example Usage.\n * ```js\n * const str = binary_to_base58([15, 239, 64])\n * console.log(str)\n * ```\n * Logged output will be 6MRy.\n */\nfunction binary_to_base58(uint8array) {\n const result = [];\n\n for (const byte of uint8array) {\n let carry = byte;\n for (let j = 0; j < result.length; ++j) {\n // @ts-ignore\n const x = (base58Map[result[j]] << 8) + carry;\n result[j] = base58_chars.charCodeAt(x % 58);\n carry = (x / 58) | 0;\n }\n while (carry) {\n result.push(base58_chars.charCodeAt(carry % 58));\n carry = (carry / 58) | 0;\n }\n }\n\n for (const byte of uint8array)\n if (byte) break;\n else result.push(\"1\".charCodeAt(0));\n\n result.reverse();\n\n return String.fromCharCode(...result);\n}\n\nexport default binary_to_base58;\n","/**\n * base64.ts\n *\n * Licensed under the BSD 3-Clause License.\n * http://opensource.org/licenses/BSD-3-Clause\n *\n * References:\n * http://en.wikipedia.org/wiki/Base64\n *\n * @author Dan Kogai (https://github.com/dankogai)\n */\nconst version = '3.7.7';\n/**\n * @deprecated use lowercase `version`.\n */\nconst VERSION = version;\nconst _hasBuffer = typeof Buffer === 'function';\nconst _TD = typeof TextDecoder === 'function' ? new TextDecoder() : undefined;\nconst _TE = typeof TextEncoder === 'function' ? new TextEncoder() : undefined;\nconst b64ch = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';\nconst b64chs = Array.prototype.slice.call(b64ch);\nconst b64tab = ((a) => {\n let tab = {};\n a.forEach((c, i) => tab[c] = i);\n return tab;\n})(b64chs);\nconst b64re = /^(?:[A-Za-z\\d+\\/]{4})*?(?:[A-Za-z\\d+\\/]{2}(?:==)?|[A-Za-z\\d+\\/]{3}=?)?$/;\nconst _fromCC = String.fromCharCode.bind(String);\nconst _U8Afrom = typeof Uint8Array.from === 'function'\n ? Uint8Array.from.bind(Uint8Array)\n : (it) => new Uint8Array(Array.prototype.slice.call(it, 0));\nconst _mkUriSafe = (src) => src\n .replace(/=/g, '').replace(/[+\\/]/g, (m0) => m0 == '+' ? '-' : '_');\nconst _tidyB64 = (s) => s.replace(/[^A-Za-z0-9\\+\\/]/g, '');\n/**\n * polyfill version of `btoa`\n */\nconst btoaPolyfill = (bin) => {\n // console.log('polyfilled');\n let u32, c0, c1, c2, asc = '';\n const pad = bin.length % 3;\n for (let i = 0; i < bin.length;) {\n if ((c0 = bin.charCodeAt(i++)) > 255 ||\n (c1 = bin.charCodeAt(i++)) > 255 ||\n (c2 = bin.charCodeAt(i++)) > 255)\n throw new TypeError('invalid character found');\n u32 = (c0 << 16) | (c1 << 8) | c2;\n asc += b64chs[u32 >> 18 & 63]\n + b64chs[u32 >> 12 & 63]\n + b64chs[u32 >> 6 & 63]\n + b64chs[u32 & 63];\n }\n return pad ? asc.slice(0, pad - 3) + \"===\".substring(pad) : asc;\n};\n/**\n * does what `window.btoa` of web browsers do.\n * @param {String} bin binary string\n * @returns {string} Base64-encoded string\n */\nconst _btoa = typeof btoa === 'function' ? (bin) => btoa(bin)\n : _hasBuffer ? (bin) => Buffer.from(bin, 'binary').toString('base64')\n : btoaPolyfill;\nconst _fromUint8Array = _hasBuffer\n ? (u8a) => Buffer.from(u8a).toString('base64')\n : (u8a) => {\n // cf. https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string/12713326#12713326\n const maxargs = 0x1000;\n let strs = [];\n for (let i = 0, l = u8a.length; i < l; i += maxargs) {\n strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs)));\n }\n return _btoa(strs.join(''));\n };\n/**\n * converts a Uint8Array to a Base64 string.\n * @param {boolean} [urlsafe] URL-and-filename-safe a la RFC4648 §5\n * @returns {string} Base64 string\n */\nconst fromUint8Array = (u8a, urlsafe = false) => urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a);\n// This trick is found broken https://github.com/dankogai/js-base64/issues/130\n// const utob = (src: string) => unescape(encodeURIComponent(src));\n// reverting good old fationed regexp\nconst cb_utob = (c) => {\n if (c.length < 2) {\n var cc = c.charCodeAt(0);\n return cc < 0x80 ? c\n : cc < 0x800 ? (_fromCC(0xc0 | (cc >>> 6))\n + _fromCC(0x80 | (cc & 0x3f)))\n : (_fromCC(0xe0 | ((cc >>> 12) & 0x0f))\n + _fromCC(0x80 | ((cc >>> 6) & 0x3f))\n + _fromCC(0x80 | (cc & 0x3f)));\n }\n else {\n var cc = 0x10000\n + (c.charCodeAt(0) - 0xD800) * 0x400\n + (c.charCodeAt(1) - 0xDC00);\n return (_fromCC(0xf0 | ((cc >>> 18) & 0x07))\n + _fromCC(0x80 | ((cc >>> 12) & 0x3f))\n + _fromCC(0x80 | ((cc >>> 6) & 0x3f))\n + _fromCC(0x80 | (cc & 0x3f)));\n }\n};\nconst re_utob = /[\\uD800-\\uDBFF][\\uDC00-\\uDFFFF]|[^\\x00-\\x7F]/g;\n/**\n * @deprecated should have been internal use only.\n * @param {string} src UTF-8 string\n * @returns {string} UTF-16 string\n */\nconst utob = (u) => u.replace(re_utob, cb_utob);\n//\nconst _encode = _hasBuffer\n ? (s) => Buffer.from(s, 'utf8').toString('base64')\n : _TE\n ? (s) => _fromUint8Array(_TE.encode(s))\n : (s) => _btoa(utob(s));\n/**\n * converts a UTF-8-encoded string to a Base64 string.\n * @param {boolean} [urlsafe] if `true` make the result URL-safe\n * @returns {string} Base64 string\n */\nconst encode = (src, urlsafe = false) => urlsafe\n ? _mkUriSafe(_encode(src))\n : _encode(src);\n/**\n * converts a UTF-8-encoded string to URL-safe Base64 RFC4648 §5.\n * @returns {string} Base64 string\n */\nconst encodeURI = (src) => encode(src, true);\n// This trick is found broken https://github.com/dankogai/js-base64/issues/130\n// const btou = (src: string) => decodeURIComponent(escape(src));\n// reverting good old fationed regexp\nconst re_btou = /[\\xC0-\\xDF][\\x80-\\xBF]|[\\xE0-\\xEF][\\x80-\\xBF]{2}|[\\xF0-\\xF7][\\x80-\\xBF]{3}/g;\nconst cb_btou = (cccc) => {\n switch (cccc.length) {\n case 4:\n var cp = ((0x07 & cccc.charCodeAt(0)) << 18)\n | ((0x3f & cccc.charCodeAt(1)) << 12)\n | ((0x3f & cccc.charCodeAt(2)) << 6)\n | (0x3f & cccc.charCodeAt(3)), offset = cp - 0x10000;\n return (_fromCC((offset >>> 10) + 0xD800)\n + _fromCC((offset & 0x3FF) + 0xDC00));\n case 3:\n return _fromCC(((0x0f & cccc.charCodeAt(0)) << 12)\n | ((0x3f & cccc.charCodeAt(1)) << 6)\n | (0x3f & cccc.charCodeAt(2)));\n default:\n return _fromCC(((0x1f & cccc.charCodeAt(0)) << 6)\n | (0x3f & cccc.charCodeAt(1)));\n }\n};\n/**\n * @deprecated should have been internal use only.\n * @param {string} src UTF-16 string\n * @returns {string} UTF-8 string\n */\nconst btou = (b) => b.replace(re_btou, cb_btou);\n/**\n * polyfill version of `atob`\n */\nconst atobPolyfill = (asc) => {\n // console.log('polyfilled');\n asc = asc.replace(/\\s+/g, '');\n if (!b64re.test(asc))\n throw new TypeError('malformed base64.');\n asc += '=='.slice(2 - (asc.length & 3));\n let u24, bin = '', r1, r2;\n for (let i = 0; i < asc.length;) {\n u24 = b64tab[asc.charAt(i++)] << 18\n | b64tab[asc.charAt(i++)] << 12\n | (r1 = b64tab[asc.charAt(i++)]) << 6\n | (r2 = b64tab[asc.charAt(i++)]);\n bin += r1 === 64 ? _fromCC(u24 >> 16 & 255)\n : r2 === 64 ? _fromCC(u24 >> 16 & 255, u24 >> 8 & 255)\n : _fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255);\n }\n return bin;\n};\n/**\n * does what `window.atob` of web browsers do.\n * @param {String} asc Base64-encoded string\n * @returns {string} binary string\n */\nconst _atob = typeof atob === 'function' ? (asc) => atob(_tidyB64(asc))\n : _hasBuffer ? (asc) => Buffer.from(asc, 'base64').toString('binary')\n : atobPolyfill;\n//\nconst _toUint8Array = _hasBuffer\n ? (a) => _U8Afrom(Buffer.from(a, 'base64'))\n : (a) => _U8Afrom(_atob(a).split('').map(c => c.charCodeAt(0)));\n/**\n * converts a Base64 string to a Uint8Array.\n */\nconst toUint8Array = (a) => _toUint8Array(_unURI(a));\n//\nconst _decode = _hasBuffer\n ? (a) => Buffer.from(a, 'base64').toString('utf8')\n : _TD\n ? (a) => _TD.decode(_toUint8Array(a))\n : (a) => btou(_atob(a));\nconst _unURI = (a) => _tidyB64(a.replace(/[-_]/g, (m0) => m0 == '-' ? '+' : '/'));\n/**\n * converts a Base64 string to a UTF-8 string.\n * @param {String} src Base64 string. Both normal and URL-safe are supported\n * @returns {string} UTF-8 string\n */\nconst decode = (src) => _decode(_unURI(src));\n/**\n * check if a value is a valid Base64 string\n * @param {String} src a value to check\n */\nconst isValid = (src) => {\n if (typeof src !== 'string')\n return false;\n const s = src.replace(/\\s+/g, '').replace(/={0,2}$/, '');\n return !/[^\\s0-9a-zA-Z\\+/]/.test(s) || !/[^\\s0-9a-zA-Z\\-_]/.test(s);\n};\n//\nconst _noEnum = (v) => {\n return {\n value: v, enumerable: false, writable: true, configurable: true\n };\n};\n/**\n * extend String.prototype with relevant methods\n */\nconst extendString = function () {\n const _add = (name, body) => Object.defineProperty(String.prototype, name, _noEnum(body));\n _add('fromBase64', function () { return decode(this); });\n _add('toBase64', function (urlsafe) { return encode(this, urlsafe); });\n _add('toBase64URI', function () { return encode(this, true); });\n _add('toBase64URL', function () { return encode(this, true); });\n _add('toUint8Array', function () { return toUint8Array(this); });\n};\n/**\n * extend Uint8Array.prototype with relevant methods\n */\nconst extendUint8Array = function () {\n const _add = (name, body) => Object.defineProperty(Uint8Array.prototype, name, _noEnum(body));\n _add('toBase64', function (urlsafe) { return fromUint8Array(this, urlsafe); });\n _add('toBase64URI', function () { return fromUint8Array(this, true); });\n _add('toBase64URL', function () { return fromUint8Array(this, true); });\n};\n/**\n * extend Builtin prototypes with relevant methods\n */\nconst extendBuiltins = () => {\n extendString();\n extendUint8Array();\n};\nconst gBase64 = {\n version: version,\n VERSION: VERSION,\n atob: _atob,\n atobPolyfill: atobPolyfill,\n btoa: _btoa,\n btoaPolyfill: btoaPolyfill,\n fromBase64: decode,\n toBase64: encode,\n encode: encode,\n encodeURI: encodeURI,\n encodeURL: encodeURI,\n utob: utob,\n btou: btou,\n decode: decode,\n isValid: isValid,\n fromUint8Array: fromUint8Array,\n toUint8Array: toUint8Array,\n extendString: extendString,\n extendUint8Array: extendUint8Array,\n extendBuiltins: extendBuiltins\n};\n// makecjs:CUT //\nexport { version };\nexport { VERSION };\nexport { _atob as atob };\nexport { atobPolyfill };\nexport { _btoa as btoa };\nexport { btoaPolyfill };\nexport { decode as fromBase64 };\nexport { encode as toBase64 };\nexport { utob };\nexport { encode };\nexport { encodeURI };\nexport { encodeURI as encodeURL };\nexport { btou };\nexport { decode };\nexport { isValid };\nexport { fromUint8Array };\nexport { toUint8Array };\nexport { extendString };\nexport { extendUint8Array };\nexport { extendBuiltins };\n// and finally,\nexport { gBase64 as Base64 };\n","export const LsPrefix = \"__fastnear_\";\n\nexport interface StorageBackend {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n clear(): void;\n}\n\n// Default: Use `localStorage` if available, otherwise an in-memory fallback\nexport const createDefaultStorage = (): StorageBackend =>\n typeof localStorage !== \"undefined\"\n ? localStorage\n : {\n getItem: (key) => memoryStore.get(key) || null,\n setItem: (key, value) => memoryStore.set(key, value),\n removeItem: (key) => memoryStore.delete(key),\n clear: () => memoryStore.clear(),\n };\n\nexport const memoryStore = new Map(); // Internal memory storage\n\nlet storageBackend: StorageBackend = createDefaultStorage();\n\n// Functional storage module\nexport const storage = {\n setBackend: (customBackend: StorageBackend) => {\n storageBackend = customBackend;\n },\n\n set: (key: string, value: any) => {\n if (value === null || value === undefined) {\n storageBackend.removeItem(LsPrefix + key);\n } else {\n storageBackend.setItem(LsPrefix + key, JSON.stringify(value));\n }\n },\n\n get: (key: string): any => {\n const value = storageBackend.getItem(LsPrefix + key);\n if (value === null) return null;\n try {\n return JSON.parse(value);\n } catch {\n return value; // Return raw string if not JSON\n }\n },\n\n remove: (key: string) => storageBackend.removeItem(key),\n clear: () => storageBackend.clear(),\n};\n","import {\n binary_to_base58 as toBase58,\n base58_to_binary as fromBase58,\n} from \"base58-js\";\nimport Big from \"big.js\";\nimport {\n encode as JsBase64Encode,\n decode as JsBase64Decode,\n fromUint8Array as JsBase64FromUint8Array,\n toUint8Array as JsBase64ToUint8Array\n} from 'js-base64';\nimport { storage } from \"./storage.js\";\n\nexport { toBase58, fromBase58 };\n\nexport function toHex(data: Uint8Array): string {\n return Array.from(data)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\nexport function fromHex(hex: string): Uint8Array {\n if (hex.length % 2) throw new Error('Hex string must be even length');\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i/2] = parseInt(hex.slice(i, i + 2), 16);\n }\n return bytes;\n}\n\nexport function base64ToBytes(b64Val: string): Uint8Array {\n return JsBase64ToUint8Array(b64Val);\n}\n\nexport function bytesToBase64(bytesArr: Uint8Array): string {\n return JsBase64FromUint8Array(bytesArr);\n}\n\nexport function toBase64(strVal: string) {\n try {\n return JsBase64Encode(strVal);\n } catch (e) {\n console.error('Issue base64 encoding', e);\n return null;\n }\n}\n\nexport function fromBase64(strVal: string) {\n try {\n return JsBase64Decode(strVal);\n } catch (e) {\n console.error('Issue base64 decoding', e);\n return null;\n }\n}\n\nexport function convertUnit(s: string | TemplateStringsArray, ...args: any[]): string {\n // Reconstruct raw string from template literal\n if (Array.isArray(s)) {\n s = s.reduce((acc, part, i) => {\n return acc + (args[i - 1] ?? \"\") + part;\n });\n }\n // Convert from `100 NEAR` into yoctoNear\n if (typeof s == \"string\") {\n const match = s.match(/([0-9.,_]+)\\s*([a-zA-Z]+)?/);\n if (match) {\n const amount = match[1].replace(/[_,]/g, \"\");\n const unitPart = match[2];\n if (unitPart) {\n switch (unitPart.toLowerCase()) {\n case \"near\":\n return Big(amount).mul(Big(10).pow(24)).toFixed(0);\n case \"tgas\":\n return Big(amount).mul(Big(10).pow(12)).toFixed(0);\n case \"ggas\":\n return Big(amount).mul(Big(10).pow(9)).toFixed(0);\n case \"gas\":\n case \"yoctonear\":\n return Big(amount).toFixed(0);\n default:\n throw new Error(`Unknown unit: ${unitPart}`);\n }\n } else {\n return Big(amount).toFixed(0);\n }\n }\n }\n return Big(`${s}`).toFixed(0);\n}\n\nexport function lsSet(key: string, value: any) {\n storage.set(key, value);\n}\n\nexport function lsGet(key: string): any {\n return storage.get(key);\n}\n\nexport function deepCopy(obj) {\n return JSON.parse(JSON.stringify(obj));\n}\n\nexport function tryParseJson(...args) {\n try {\n return JSON.parse(args[0]);\n } catch {\n if (args.length > 1) {\n return args[1];\n }\n return args[0];\n }\n}\n\nexport function parseJsonFromBytes(bytes: Uint8Array) {\n try {\n const decoder = new TextDecoder();\n return JSON.parse(\n decoder.decode(bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes))\n );\n } catch (e) {\n try {\n return bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);\n } catch (e) {\n return bytes;\n }\n }\n}\n\nexport function canSignWithLAK(actions) {\n return (\n actions.length === 1 &&\n actions[0].type === \"FunctionCall\" &&\n Big(actions[0]?.deposit ?? \"0\").eq(0)\n );\n}\n","import { ed25519 } from \"@noble/curves/ed25519\";\nimport { sha256 } from \"@noble/hashes/sha2\";\nimport { fromBase58, toBase58 } from \"./misc.js\";\nimport { Hex } from \"@noble/curves/abstract/utils\";\n\nexport { sha256 };\n\nexport const keyFromString = (key) =>\n fromBase58(\n key.includes(\":\")\n ? (() => {\n const [curve, keyPart] = key.split(\":\");\n if (curve !== \"ed25519\") {\n throw new Error(`Unsupported curve: ${curve}`);\n }\n return keyPart;\n })()\n : key,\n );\n\nexport const keyToString = (key: Uint8Array) => `ed25519:${toBase58(key)}`;\n\nexport function publicKeyFromPrivate(privateKey: string) {\n const secret = keyFromString(privateKey).slice(0, 32);\n const publicKey = ed25519.getPublicKey(secret);\n return keyToString(publicKey);\n}\n\nexport function privateKeyFromRandom() {\n const privateKey = crypto.getRandomValues(new Uint8Array(64));\n return keyToString(privateKey);\n}\n\nexport function signHash(hashBytes: Uint8Array, privateKey: string, opts?: any): Hex {\n const secret = keyFromString(privateKey).slice(0, 32);\n const signature = ed25519.sign(hashBytes, secret);\n\n if (opts?.returnBase58) {\n return toBase58(signature);\n }\n\n return signature;\n}\n\nexport function signBytes(bytes: Uint8Array, privateKey: string) {\n const hash = sha256(bytes);\n return signHash(hash, privateKey);\n}\n","export var integers = ['u8', 'u16', 'u32', 'u64', 'u128', 'i8', 'i16', 'i32', 'i64', 'i128', 'f32', 'f64'];\n","var EncodeBuffer = /** @class */ (function () {\n function EncodeBuffer() {\n this.offset = 0;\n this.buffer_size = 256;\n this.buffer = new ArrayBuffer(this.buffer_size);\n this.view = new DataView(this.buffer);\n }\n EncodeBuffer.prototype.resize_if_necessary = function (needed_space) {\n if (this.buffer_size - this.offset < needed_space) {\n this.buffer_size = Math.max(this.buffer_size * 2, this.buffer_size + needed_space);\n var new_buffer = new ArrayBuffer(this.buffer_size);\n new Uint8Array(new_buffer).set(new Uint8Array(this.buffer));\n this.buffer = new_buffer;\n this.view = new DataView(new_buffer);\n }\n };\n EncodeBuffer.prototype.get_used_buffer = function () {\n return new Uint8Array(this.buffer).slice(0, this.offset);\n };\n EncodeBuffer.prototype.store_value = function (value, type) {\n var bSize = type.substring(1);\n var size = parseInt(bSize) / 8;\n this.resize_if_necessary(size);\n var toCall = type[0] === 'f' ? \"setFloat\".concat(bSize) : type[0] === 'i' ? \"setInt\".concat(bSize) : \"setUint\".concat(bSize);\n this.view[toCall](this.offset, value, true);\n this.offset += size;\n };\n EncodeBuffer.prototype.store_bytes = function (from) {\n this.resize_if_necessary(from.length);\n new Uint8Array(this.buffer).set(new Uint8Array(from), this.offset);\n this.offset += from.length;\n };\n return EncodeBuffer;\n}());\nexport { EncodeBuffer };\nvar DecodeBuffer = /** @class */ (function () {\n function DecodeBuffer(buf) {\n this.offset = 0;\n this.buffer_size = buf.length;\n this.buffer = new ArrayBuffer(buf.length);\n new Uint8Array(this.buffer).set(buf);\n this.view = new DataView(this.buffer);\n }\n DecodeBuffer.prototype.assert_enough_buffer = function (size) {\n if (this.offset + size > this.buffer.byteLength) {\n throw new Error('Error in schema, the buffer is smaller than expected');\n }\n };\n DecodeBuffer.prototype.consume_value = function (type) {\n var bSize = type.substring(1);\n var size = parseInt(bSize) / 8;\n this.assert_enough_buffer(size);\n var toCall = type[0] === 'f' ? \"getFloat\".concat(bSize) : type[0] === 'i' ? \"getInt\".concat(bSize) : \"getUint\".concat(bSize);\n var ret = this.view[toCall](this.offset, true);\n this.offset += size;\n return ret;\n };\n DecodeBuffer.prototype.consume_bytes = function (size) {\n this.assert_enough_buffer(size);\n var ret = this.buffer.slice(this.offset, this.offset + size);\n this.offset += size;\n return ret;\n };\n return DecodeBuffer;\n}());\nexport { DecodeBuffer };\n","var __extends = (this && this.__extends) || (function () {\n var extendStatics = function (d, b) {\n extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\n return extendStatics(d, b);\n };\n return function (d, b) {\n if (typeof b !== \"function\" && b !== null)\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n };\n})();\nimport { integers } from './types.js';\nexport function isArrayLike(value) {\n // source: https://stackoverflow.com/questions/24048547/checking-if-an-object-is-array-like\n return (Array.isArray(value) ||\n (!!value &&\n typeof value === 'object' &&\n 'length' in value &&\n typeof (value.length) === 'number' &&\n (value.length === 0 ||\n (value.length > 0 &&\n (value.length - 1) in value))));\n}\nexport function expect_type(value, type, fieldPath) {\n if (typeof (value) !== type) {\n throw new Error(\"Expected \".concat(type, \" not \").concat(typeof (value), \"(\").concat(value, \") at \").concat(fieldPath.join('.')));\n }\n}\nexport function expect_bigint(value, fieldPath) {\n var basicType = ['number', 'string', 'bigint', 'boolean'].includes(typeof (value));\n var strObject = typeof (value) === 'object' && value !== null && 'toString' in value;\n if (!basicType && !strObject) {\n throw new Error(\"Expected bigint, number, boolean or string not \".concat(typeof (value), \"(\").concat(value, \") at \").concat(fieldPath.join('.')));\n }\n}\nexport function expect_same_size(length, expected, fieldPath) {\n if (length !== expected) {\n throw new Error(\"Array length \".concat(length, \" does not match schema length \").concat(expected, \" at \").concat(fieldPath.join('.')));\n }\n}\nexport function expect_enum(value, fieldPath) {\n if (typeof (value) !== 'object' || value === null) {\n throw new Error(\"Expected object not \".concat(typeof (value), \"(\").concat(value, \") at \").concat(fieldPath.join('.')));\n }\n}\n// Validate Schema\nvar VALID_STRING_TYPES = integers.concat(['bool', 'string']);\nvar VALID_OBJECT_KEYS = ['option', 'enum', 'array', 'set', 'map', 'struct'];\nvar ErrorSchema = /** @class */ (function (_super) {\n __extends(ErrorSchema, _super);\n function ErrorSchema(schema, expected) {\n var message = \"Invalid schema: \".concat(JSON.stringify(schema), \" expected \").concat(expected);\n return _super.call(this, message) || this;\n }\n return ErrorSchema;\n}(Error));\nexport { ErrorSchema };\nexport function validate_schema(schema) {\n if (typeof (schema) === 'string' && VALID_STRING_TYPES.includes(schema)) {\n return;\n }\n if (schema && typeof (schema) === 'object') {\n var keys = Object.keys(schema);\n if (keys.length === 1 && VALID_OBJECT_KEYS.includes(keys[0])) {\n var key = keys[0];\n if (key === 'option')\n return validate_schema(schema[key]);\n if (key === 'enum')\n return validate_enum_schema(schema[key]);\n if (key === 'array')\n return validate_array_schema(schema[key]);\n if (key === 'set')\n return validate_schema(schema[key]);\n if (key === 'map')\n return validate_map_schema(schema[key]);\n if (key === 'struct')\n return validate_struct_schema(schema[key]);\n }\n }\n throw new ErrorSchema(schema, VALID_OBJECT_KEYS.join(', ') + ' or ' + VALID_STRING_TYPES.join(', '));\n}\nfunction validate_enum_schema(schema) {\n if (!Array.isArray(schema))\n throw new ErrorSchema(schema, 'Array');\n for (var _i = 0, schema_1 = schema; _i < schema_1.length; _i++) {\n var sch = schema_1[_i];\n if (typeof sch !== 'object' || !('struct' in sch)) {\n throw new Error('Missing \"struct\" key in enum schema');\n }\n if (typeof sch.struct !== 'object' || Object.keys(sch.struct).length !== 1) {\n throw new Error('The \"struct\" in each enum must have a single key');\n }\n validate_schema({ struct: sch.struct });\n }\n}\nfunction validate_array_schema(schema) {\n if (typeof schema !== 'object')\n throw new ErrorSchema(schema, '{ type, len? }');\n if (schema.len && typeof schema.len !== 'number') {\n throw new Error(\"Invalid schema: \".concat(schema));\n }\n if ('type' in schema)\n return validate_schema(schema.type);\n throw new ErrorSchema(schema, '{ type, len? }');\n}\nfunction validate_map_schema(schema) {\n if (typeof schema === 'object' && 'key' in schema && 'value' in schema) {\n validate_schema(schema.key);\n validate_schema(schema.value);\n }\n else {\n throw new ErrorSchema(schema, '{ key, value }');\n }\n}\nfunction validate_struct_schema(schema) {\n if (typeof schema !== 'object')\n throw new ErrorSchema(schema, 'object');\n for (var key in schema) {\n validate_schema(schema[key]);\n }\n}\n","import { integers } from './types.js';\nimport { EncodeBuffer } from './buffer.js';\nimport * as utils from './utils.js';\nvar BorshSerializer = /** @class */ (function () {\n function BorshSerializer(checkTypes) {\n this.encoded = new EncodeBuffer();\n this.fieldPath = ['value'];\n this.checkTypes = checkTypes;\n }\n BorshSerializer.prototype.encode = function (value, schema) {\n this.encode_value(value, schema);\n return this.encoded.get_used_buffer();\n };\n BorshSerializer.prototype.encode_value = function (value, schema) {\n if (typeof schema === 'string') {\n if (integers.includes(schema))\n return this.encode_integer(value, schema);\n if (schema === 'string')\n return this.encode_string(value);\n if (schema === 'bool')\n return this.encode_boolean(value);\n }\n if (typeof schema === 'object') {\n if ('option' in schema)\n return this.encode_option(value, schema);\n if ('enum' in schema)\n return this.encode_enum(value, schema);\n if ('array' in schema)\n return this.encode_array(value, schema);\n if ('set' in schema)\n return this.encode_set(value, schema);\n if ('map' in schema)\n return this.encode_map(value, schema);\n if ('struct' in schema)\n return this.encode_struct(value, schema);\n }\n };\n BorshSerializer.prototype.encode_integer = function (value, schema) {\n var size = parseInt(schema.substring(1));\n if (size <= 32 || schema == 'f64') {\n this.checkTypes && utils.expect_type(value, 'number', this.fieldPath);\n this.encoded.store_value(value, schema);\n }\n else {\n this.checkTypes && utils.expect_bigint(value, this.fieldPath);\n this.encode_bigint(BigInt(value), size);\n }\n };\n BorshSerializer.prototype.encode_bigint = function (value, size) {\n var buffer_len = size / 8;\n var buffer = new Uint8Array(buffer_len);\n for (var i = 0; i < buffer_len; i++) {\n buffer[i] = Number(value & BigInt(0xff));\n value = value >> BigInt(8);\n }\n this.encoded.store_bytes(new Uint8Array(buffer));\n };\n BorshSerializer.prototype.encode_string = function (value) {\n this.checkTypes && utils.expect_type(value, 'string', this.fieldPath);\n var _value = value;\n // encode to utf8 bytes without using TextEncoder\n var utf8Bytes = [];\n for (var i = 0; i < _value.length; i++) {\n var charCode = _value.charCodeAt(i);\n if (charCode < 0x80) {\n utf8Bytes.push(charCode);\n }\n else if (charCode < 0x800) {\n utf8Bytes.push(0xc0 | (charCode >> 6), 0x80 | (charCode & 0x3f));\n }\n else if (charCode < 0xd800 || charCode >= 0xe000) {\n utf8Bytes.push(0xe0 | (charCode >> 12), 0x80 | ((charCode >> 6) & 0x3f), 0x80 | (charCode & 0x3f));\n }\n else {\n i++;\n charCode = 0x10000 + (((charCode & 0x3ff) << 10) | (_value.charCodeAt(i) & 0x3ff));\n utf8Bytes.push(0xf0 | (charCode >> 18), 0x80 | ((charCode >> 12) & 0x3f), 0x80 | ((charCode >> 6) & 0x3f), 0x80 | (charCode & 0x3f));\n }\n }\n // 4 bytes for length + string bytes\n this.encoded.store_value(utf8Bytes.length, 'u32');\n this.encoded.store_bytes(new Uint8Array(utf8Bytes));\n };\n BorshSerializer.prototype.encode_boolean = function (value) {\n this.checkTypes && utils.expect_type(value, 'boolean', this.fieldPath);\n this.encoded.store_value(value ? 1 : 0, 'u8');\n };\n BorshSerializer.prototype.encode_option = function (value, schema) {\n if (value === null || value === undefined) {\n this.encoded.store_value(0, 'u8');\n }\n else {\n this.encoded.store_value(1, 'u8');\n this.encode_value(value, schema.option);\n }\n };\n BorshSerializer.prototype.encode_enum = function (value, schema) {\n this.checkTypes && utils.expect_enum(value, this.fieldPath);\n var valueKey = Object.keys(value)[0];\n for (var i = 0; i < schema[\"enum\"].length; i++) {\n var valueSchema = schema[\"enum\"][i];\n if (valueKey === Object.keys(valueSchema.struct)[0]) {\n this.encoded.store_value(i, 'u8');\n return this.encode_struct(value, valueSchema);\n }\n }\n throw new Error(\"Enum key (\".concat(valueKey, \") not found in enum schema: \").concat(JSON.stringify(schema), \" at \").concat(this.fieldPath.join('.')));\n };\n BorshSerializer.prototype.encode_array = function (value, schema) {\n if (utils.isArrayLike(value))\n return this.encode_arraylike(value, schema);\n if (value instanceof ArrayBuffer)\n return this.encode_buffer(value, schema);\n throw new Error(\"Expected Array-like not \".concat(typeof (value), \"(\").concat(value, \") at \").concat(this.fieldPath.join('.')));\n };\n BorshSerializer.prototype.encode_arraylike = function (value, schema) {\n if (schema.array.len) {\n utils.expect_same_size(value.length, schema.array.len, this.fieldPath);\n }\n else {\n // 4 bytes for length\n this.encoded.store_value(value.length, 'u32');\n }\n // array values\n for (var i = 0; i < value.length; i++) {\n this.encode_value(value[i], schema.array.type);\n }\n };\n BorshSerializer.prototype.encode_buffer = function (value, schema) {\n if (schema.array.len) {\n utils.expect_same_size(value.byteLength, schema.array.len, this.fieldPath);\n }\n else {\n // 4 bytes for length\n this.encoded.store_value(value.byteLength, 'u32');\n }\n // array values\n this.encoded.store_bytes(new Uint8Array(value));\n };\n BorshSerializer.prototype.encode_set = function (value, schema) {\n this.checkTypes && utils.expect_type(value, 'object', this.fieldPath);\n var isSet = value instanceof Set;\n var values = isSet ? Array.from(value.values()) : Object.values(value);\n // 4 bytes for length\n this.encoded.store_value(values.length, 'u32');\n // set values\n for (var _i = 0, values_1 = values; _i < values_1.length; _i++) {\n var value_1 = values_1[_i];\n this.encode_value(value_1, schema.set);\n }\n };\n BorshSerializer.prototype.encode_map = function (value, schema) {\n this.checkTypes && utils.expect_type(value, 'object', this.fieldPath);\n var isMap = value instanceof Map;\n var keys = isMap ? Array.from(value.keys()) : Object.keys(value);\n // 4 bytes for length\n this.encoded.store_value(keys.length, 'u32');\n // store key/values\n for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {\n var key = keys_1[_i];\n this.encode_value(key, schema.map.key);\n this.encode_value(isMap ? value.get(key) : value[key], schema.map.value);\n }\n };\n BorshSerializer.prototype.encode_struct = function (value, schema) {\n this.checkTypes && utils.expect_type(value, 'object', this.fieldPath);\n for (var _i = 0, _a = Object.keys(schema.struct); _i < _a.length; _i++) {\n var key = _a[_i];\n this.fieldPath.push(key);\n this.encode_value(value[key], schema.struct[key]);\n this.fieldPath.pop();\n }\n };\n return BorshSerializer;\n}());\nexport { BorshSerializer };\n","import { integers } from './types.js';\nimport { DecodeBuffer } from './buffer.js';\nvar BorshDeserializer = /** @class */ (function () {\n function BorshDeserializer(bufferArray) {\n this.buffer = new DecodeBuffer(bufferArray);\n }\n BorshDeserializer.prototype.decode = function (schema) {\n return this.decode_value(schema);\n };\n BorshDeserializer.prototype.decode_value = function (schema) {\n if (typeof schema === 'string') {\n if (integers.includes(schema))\n return this.decode_integer(schema);\n if (schema === 'string')\n return this.decode_string();\n if (schema === 'bool')\n return this.decode_boolean();\n }\n if (typeof schema === 'object') {\n if ('option' in schema)\n return this.decode_option(schema);\n if ('enum' in schema)\n return this.decode_enum(schema);\n if ('array' in schema)\n return this.decode_array(schema);\n if ('set' in schema)\n return this.decode_set(schema);\n if ('map' in schema)\n return this.decode_map(schema);\n if ('struct' in schema)\n return this.decode_struct(schema);\n }\n throw new Error(\"Unsupported type: \".concat(schema));\n };\n BorshDeserializer.prototype.decode_integer = function (schema) {\n var size = parseInt(schema.substring(1));\n if (size <= 32 || schema == 'f64') {\n return this.buffer.consume_value(schema);\n }\n return this.decode_bigint(size, schema.startsWith('i'));\n };\n BorshDeserializer.prototype.decode_bigint = function (size, signed) {\n if (signed === void 0) { signed = false; }\n var buffer_len = size / 8;\n var buffer = new Uint8Array(this.buffer.consume_bytes(buffer_len));\n var bits = buffer.reduceRight(function (r, x) { return r + x.toString(16).padStart(2, '0'); }, '');\n if (signed && buffer[buffer_len - 1]) {\n return BigInt.asIntN(size, BigInt(\"0x\".concat(bits)));\n }\n return BigInt(\"0x\".concat(bits));\n };\n BorshDeserializer.prototype.decode_string = function () {\n var len = this.decode_integer('u32');\n var buffer = new Uint8Array(this.buffer.consume_bytes(len));\n // decode utf-8 string without using TextDecoder\n // first get all bytes to single byte code points\n var codePoints = [];\n for (var i = 0; i < len; ++i) {\n var byte = buffer[i];\n if (byte < 0x80) {\n codePoints.push(byte);\n }\n else if (byte < 0xE0) {\n codePoints.push(((byte & 0x1F) << 6) | (buffer[++i] & 0x3F));\n }\n else if (byte < 0xF0) {\n codePoints.push(((byte & 0x0F) << 12) | ((buffer[++i] & 0x3F) << 6) | (buffer[++i] & 0x3F));\n }\n else {\n var codePoint = ((byte & 0x07) << 18) | ((buffer[++i] & 0x3F) << 12) | ((buffer[++i] & 0x3F) << 6) | (buffer[++i] & 0x3F);\n codePoints.push(codePoint);\n }\n }\n // then decode code points to utf-8\n return String.fromCodePoint.apply(String, codePoints);\n };\n BorshDeserializer.prototype.decode_boolean = function () {\n return this.buffer.consume_value('u8') > 0;\n };\n BorshDeserializer.prototype.decode_option = function (schema) {\n var option = this.buffer.consume_value('u8');\n if (option === 1) {\n return this.decode_value(schema.option);\n }\n if (option !== 0) {\n throw new Error(\"Invalid option \".concat(option));\n }\n return null;\n };\n BorshDeserializer.prototype.decode_enum = function (schema) {\n var _a;\n var valueIndex = this.buffer.consume_value('u8');\n if (valueIndex > schema[\"enum\"].length) {\n throw new Error(\"Enum option \".concat(valueIndex, \" is not available\"));\n }\n var struct = schema[\"enum\"][valueIndex].struct;\n var key = Object.keys(struct)[0];\n return _a = {}, _a[key] = this.decode_value(struct[key]), _a;\n };\n BorshDeserializer.prototype.decode_array = function (schema) {\n var result = [];\n var len = schema.array.len ? schema.array.len : this.decode_integer('u32');\n for (var i = 0; i < len; ++i) {\n result.push(this.decode_value(schema.array.type));\n }\n return result;\n };\n BorshDeserializer.prototype.decode_set = function (schema) {\n var len = this.decode_integer('u32');\n var result = new Set();\n for (var i = 0; i < len; ++i) {\n result.add(this.decode_value(schema.set));\n }\n return result;\n };\n BorshDeserializer.prototype.decode_map = function (schema) {\n var len = this.decode_integer('u32');\n var result = new Map();\n for (var i = 0; i < len; ++i) {\n var key = this.decode_value(schema.map.key);\n var value = this.decode_value(schema.map.value);\n result.set(key, value);\n }\n return result;\n };\n BorshDeserializer.prototype.decode_struct = function (schema) {\n var result = {};\n for (var key in schema.struct) {\n result[key] = this.decode_value(schema.struct[key]);\n }\n return result;\n };\n return BorshDeserializer;\n}());\nexport { BorshDeserializer };\n","import { BorshSerializer } from './serialize.js';\nimport { BorshDeserializer } from './deserialize.js';\nimport * as utils from './utils.js';\nexport function serialize(schema, value, validate) {\n if (validate === void 0) { validate = true; }\n if (validate)\n utils.validate_schema(schema);\n var serializer = new BorshSerializer(validate);\n return serializer.encode(value, schema);\n}\nexport function deserialize(schema, buffer, validate) {\n if (validate === void 0) { validate = true; }\n if (validate)\n utils.validate_schema(schema);\n var deserializer = new BorshDeserializer(buffer);\n return deserializer.decode(schema);\n}\n","import { Schema } from \"borsh\"\n\nexport const nearChainSchema = new (class BorshSchema {\n Ed25519Signature: Schema = {\n struct: {\n data: { array: { type: \"u8\", len: 64 } },\n },\n };\n Secp256k1Signature: Schema = {\n struct: {\n data: { array: { type: \"u8\", len: 65 } },\n },\n };\n Signature: Schema = {\n enum: [\n { struct: { ed25519Signature: this.Ed25519Signature } },\n { struct: { secp256k1Signature: this.Secp256k1Signature } },\n ],\n };\n Ed25519Data: Schema = {\n struct: {\n data: { array: { type: \"u8\", len: 32 } },\n },\n };\n Secp256k1Data: Schema = {\n struct: {\n data: { array: { type: \"u8\", len: 64 } },\n },\n };\n PublicKey: Schema = {\n enum: [\n { struct: { ed25519Key: this.Ed25519Data } },\n { struct: { secp256k1Key: this.Secp256k1Data } },\n ],\n };\n FunctionCallPermission: Schema = {\n struct: {\n allowance: { option: \"u128\" },\n receiverId: \"string\",\n methodNames: { array: { type: \"string\" } },\n },\n };\n FullAccessPermission: Schema = {\n struct: {},\n };\n AccessKeyPermission: Schema = {\n enum: [\n { struct: { functionCall: this.FunctionCallPermission } },\n { struct: { fullAccess: this.FullAccessPermission } },\n ],\n };\n AccessKey: Schema = {\n struct: {\n nonce: \"u64\",\n permission: this.AccessKeyPermission,\n },\n };\n CreateAccount: Schema = {\n struct: {},\n };\n DeployContract: Schema = {\n struct: {\n code: { array: { type: \"u8\" } },\n },\n };\n FunctionCall: Schema = {\n struct: {\n methodName: \"string\",\n args: { array: { type: \"u8\" } },\n gas: \"u64\",\n deposit: \"u128\",\n },\n };\n Transfer: Schema = {\n struct: {\n deposit: \"u128\",\n },\n };\n Stake: Schema = {\n struct: {\n stake: \"u128\",\n publicKey: this.PublicKey,\n },\n };\n AddKey: Schema = {\n struct: {\n publicKey: this.PublicKey,\n accessKey: this.AccessKey,\n },\n };\n DeleteKey: Schema = {\n struct: {\n publicKey: this.PublicKey,\n },\n };\n DeleteAccount: Schema = {\n struct: {\n beneficiaryId: \"string\",\n },\n };\n ClassicAction: Schema = {\n enum: [\n { struct: { createAccount: this.CreateAccount } },\n { struct: { deployContract: this.DeployContract } },\n { struct: { functionCall: this.FunctionCall } },\n { struct: { transfer: this.Transfer } },\n { struct: { stake: this.Stake } },\n { struct: { addKey: this.AddKey } },\n { struct: { deleteKey: this.DeleteKey } },\n { struct: { deleteAccount: this.DeleteAccount } },\n ],\n };\n DelegateAction: Schema = {\n struct: {\n senderId: \"string\",\n receiverId: \"string\",\n actions: { array: { type: this.ClassicAction } },\n nonce: \"u64\",\n maxBlockHeight: \"u64\",\n publicKey: this.PublicKey,\n },\n };\n SignedDelegate: Schema = {\n struct: {\n delegateAction: this.DelegateAction,\n signature: this.Signature,\n },\n };\n Action: Schema = {\n enum: [\n { struct: { createAccount: this.CreateAccount } },\n { struct: { deployContract: this.DeployContract } },\n { struct: { functionCall: this.FunctionCall } },\n { struct: { transfer: this.Transfer } },\n { struct: { stake: this.Stake } },\n { struct: { addKey: this.AddKey } },\n { struct: { deleteKey: this.DeleteKey } },\n { struct: { deleteAccount: this.DeleteAccount } },\n { struct: { signedDelegate: this.SignedDelegate } },\n ],\n };\n Transaction: Schema = {\n struct: {\n signerId: \"string\",\n publicKey: this.PublicKey,\n nonce: \"u64\",\n receiverId: \"string\",\n blockHash: { array: { type: \"u8\", len: 32 } },\n actions: { array: { type: this.Action } },\n },\n };\n SignedTransaction: Schema = {\n struct: {\n transaction: this.Transaction,\n signature: this.Signature,\n },\n };\n})();\n\nexport const getBorshSchema = () => nearChainSchema;\n","import { serialize as borshSerialize, deserialize as borshDeserialize, Schema } from \"borsh\";\nimport { keyFromString } from \"./crypto.js\";\nimport {base64ToBytes, fromBase58, fromBase64, toBase64} from \"./misc.js\";\nimport { getBorshSchema } from \"@fastnear/borsh-schema\";\n\nexport interface PlainTransaction {\n signerId: string;\n publicKey: string;\n nonce: string | bigint | number;\n receiverId: string;\n blockHash: string;\n actions: Array;\n}\n\nexport interface PlainSignedTransaction {\n transaction: object;\n signature: object;\n}\n\n// Function to return a JSON-ready version of the transaction\nexport const txToJson = (tx: PlainTransaction): Record => {\n return JSON.parse(JSON.stringify(tx, (key, value) =>\n typeof value === 'bigint' ? value.toString() : value\n ));\n};\n\n// dude let's make this better. head just couldn't find a good name\nexport const txToJsonStringified = (tx: PlainTransaction): string => {\n return JSON.stringify(txToJson(tx));\n}\n\nexport function mapTransaction(jsonTransaction: PlainTransaction) {\n return {\n signerId: jsonTransaction.signerId,\n publicKey: {\n ed25519Key: {\n data: keyFromString(jsonTransaction.publicKey)\n }\n },\n nonce: BigInt(jsonTransaction.nonce),\n receiverId: jsonTransaction.receiverId,\n blockHash: fromBase58(jsonTransaction.blockHash),\n actions: jsonTransaction.actions.map(mapAction)\n };\n}\n\nexport function serializeTransaction(jsonTransaction: PlainTransaction) {\n console.log(\"fastnear: serializing transaction\");\n\n const transaction = mapTransaction(jsonTransaction);\n console.log(\"fastnear: mapped transaction for borsh:\", transaction);\n\n return borshSerialize(SCHEMA.Transaction, transaction);\n}\n\nexport function serializeSignedTransaction(jsonTransaction: PlainTransaction, signature) {\n console.log(\"fastnear: Serializing Signed Transaction\", jsonTransaction);\n console.log('fastnear: signature', signature)\n console.log('fastnear: signature length', fromBase58(signature).length)\n\n const mappedSignedTx = mapTransaction(jsonTransaction)\n console.log('fastnear: mapped (for borsh schema) signed transaction', mappedSignedTx)\n\n const plainSignedTransaction: PlainSignedTransaction = {\n transaction: mappedSignedTx,\n signature: {\n ed25519Signature: {\n data: fromBase58(signature),\n },\n },\n };\n\n const borshSignedTx = borshSerialize(SCHEMA.SignedTransaction, plainSignedTransaction, true);\n console.log('fastnear: borsh-serialized signed transaction:', borshSignedTx);\n\n return borshSignedTx;\n}\n\nexport function mapAction(action: any): object {\n switch (action.type) {\n case \"CreateAccount\": {\n return {\n createAccount: {},\n };\n }\n case \"DeployContract\": {\n return {\n deployContract: {\n code: base64ToBytes(action.codeBase64),\n },\n };\n }\n case \"FunctionCall\": {\n return {\n functionCall: {\n methodName: action.methodName,\n args: (action.argsBase64 !== null && action.argsBase64 !== undefined) ?\n base64ToBytes(action.argsBase64) :\n (new TextEncoder().encode(JSON.stringify(action.args))),\n gas: BigInt(action.gas ?? \"300000000000000\"),\n deposit: BigInt(action.deposit ?? \"0\"),\n },\n };\n }\n case \"Transfer\": {\n return {\n transfer: {\n deposit: BigInt(action.deposit),\n },\n };\n }\n case \"Stake\": {\n return {\n stake: {\n stake: BigInt(action.stake),\n publicKey: {\n ed25519Key: {\n data: keyFromString(action.publicKey),\n },\n },\n },\n };\n }\n case \"AddKey\": {\n return {\n addKey: {\n publicKey: {\n ed25519Key: {\n data: keyFromString(action.publicKey),\n },\n },\n accessKey: {\n nonce: BigInt(action.accessKey.nonce),\n permission:\n action.accessKey.permission === \"FullAccess\"\n ? { fullAccess: {} }\n : {\n functionCall: {\n allowance: action.accessKey.allowance\n ? BigInt(action.accessKey.allowance)\n : null,\n receiverId: action.accessKey.receiverId,\n methodNames: action.accessKey.methodNames,\n },\n },\n },\n },\n };\n }\n case \"DeleteKey\": {\n return {\n deleteKey: {\n publicKey: {\n ed25519Key: {\n data: keyFromString(action.publicKey),\n },\n },\n },\n };\n }\n case \"DeleteAccount\": {\n return {\n deleteAccount: {\n beneficiaryId: action.beneficiaryId,\n },\n };\n }\n case \"SignedDelegate\": {\n return {\n signedDelegate: {\n delegateAction: mapAction(action.delegateAction),\n signature: {\n ed25519Signature: fromBase58(action.signature),\n },\n },\n };\n }\n default: {\n throw new Error(\"Not implemented action: \" + action.type);\n }\n }\n}\n\nexport const SCHEMA = getBorshSchema();\n","import {\n lsSet,\n lsGet,\n publicKeyFromPrivate,\n} from \"@fastnear/utils\";\nimport {WalletAdapter} from \"@fastnear/wallet-adapter\";\n\nexport const WIDGET_URL = \"https://js.cdn.fastnear.com\";\n\nexport const DEFAULT_NETWORK_ID = \"mainnet\";\nexport const NETWORKS = {\n testnet: {\n networkId: \"testnet\",\n nodeUrl: \"https://rpc.testnet.fastnear.com/\",\n },\n mainnet: {\n networkId: \"mainnet\",\n nodeUrl: \"https://rpc.mainnet.fastnear.com/\",\n },\n};\n\nexport interface NetworkConfig {\n networkId: string;\n nodeUrl?: string;\n walletUrl?: string;\n helperUrl?: string;\n explorerUrl?: string;\n\n [key: string]: any;\n}\n\nexport interface AppState {\n accountId?: string | null;\n privateKey?: string | null;\n lastWalletId?: string | null;\n publicKey?: string | null;\n accessKeyContractId?: string | null;\n\n [key: string]: any;\n}\n\nexport interface TxStatus {\n txId: string;\n updateTimestamp?: number;\n\n [key: string]: any;\n}\n\nexport type TxHistory = Record;\n\nexport interface EventListeners {\n account: Set<(accountId: string) => void>;\n tx: Set<(tx: TxStatus) => void>;\n}\n\nexport interface UnbroadcastedEvents {\n account: string[];\n tx: TxStatus[];\n}\n\nexport interface WalletAdapterState {\n publicKey?: string | null;\n privateKey?: string | null;\n accountId?: string | null;\n lastWalletId?: string | null;\n networkId: string;\n}\n\n\n// Load config from localStorage or default to the network's config\nexport let _config: NetworkConfig = lsGet(\"config\") || {\n ...NETWORKS[DEFAULT_NETWORK_ID]\n};\n\n// Load application state from localStorage\nexport let _state: AppState = lsGet(\"state\") || {};\n\n// Triggered by the wallet adapter\nexport const onAdapterStateUpdate = (state: WalletAdapterState) => {\n console.log(\"Adapter state update:\", state);\n const { accountId, lastWalletId, privateKey } = state;\n update({\n accountId: accountId || undefined,\n lastWalletId: lastWalletId || undefined,\n ...(privateKey ? { privateKey } : {}),\n });\n}\n\nexport const getWalletAdapterState = (): WalletAdapterState => {\n return {\n publicKey: _state.publicKey,\n accountId: _state.accountId,\n lastWalletId: _state.lastWalletId,\n networkId: _config.networkId,\n };\n}\n\n// We can create an adapter instance here\nexport let _adapter = new WalletAdapter({\n onStateUpdate: onAdapterStateUpdate,\n lastState: getWalletAdapterState(),\n widgetUrl: WIDGET_URL,\n});\n\n// Attempt to set publicKey if we have a privateKey\ntry {\n _state.publicKey = _state.privateKey\n ? publicKeyFromPrivate(_state.privateKey)\n : null;\n} catch (e) {\n console.error(\"Error parsing private key:\", e);\n _state.privateKey = null;\n lsSet(\"nonce\", null);\n}\n\n// Transaction history\nexport let _txHistory: TxHistory = lsGet(\"txHistory\") || {};\n\n\nexport const _unbroadcastedEvents: UnbroadcastedEvents = {\n account: [],\n tx: [],\n};\n\n// events / listeners\nexport const events = {\n _eventListeners: {\n account: new Set(),\n tx: new Set(),\n },\n\n notifyAccountListeners: (accountId: string) => {\n if (events._eventListeners.account.size === 0) {\n _unbroadcastedEvents.account.push(accountId);\n return;\n }\n events._eventListeners.account.forEach((callback: any) => {\n try {\n callback(accountId);\n } catch (e) {\n console.error(e);\n }\n });\n },\n\n notifyTxListeners: (tx: TxStatus) => {\n if (events._eventListeners.tx.size === 0) {\n _unbroadcastedEvents.tx.push(tx);\n return;\n }\n events._eventListeners.tx.forEach((callback: any) => {\n try {\n callback(tx);\n } catch (e) {\n console.error(e);\n }\n });\n },\n\n onAccount: (callback: (accountId: string) => void) => {\n events._eventListeners.account.add(callback);\n if (_unbroadcastedEvents.account.length > 0) {\n const accountEvent = _unbroadcastedEvents.account;\n _unbroadcastedEvents.account = [];\n accountEvent.forEach(events.notifyAccountListeners);\n }\n },\n\n onTx: (callback: (tx: TxStatus) => void): void => {\n events._eventListeners.tx.add(callback);\n if (_unbroadcastedEvents.tx.length > 0) {\n const txEvent = _unbroadcastedEvents.tx;\n _unbroadcastedEvents.tx = [];\n txEvent.forEach(events.notifyTxListeners);\n }\n }\n}\n\n// Mutators\n// @todo: in favor of limiting when out of alpha\n// but haven't given it enough thought ~ mike\nexport const update = (newState: Partial) => {\n const oldState = _state;\n _state = {..._state, ...newState};\n\n lsSet(\"state\", {\n accountId: _state.accountId,\n privateKey: _state.privateKey,\n lastWalletId: _state.lastWalletId,\n accessKeyContractId: _state.accessKeyContractId,\n });\n\n if (\n newState.hasOwnProperty(\"privateKey\") &&\n newState.privateKey !== oldState.privateKey\n ) {\n _state.publicKey = newState.privateKey\n ? publicKeyFromPrivate(newState.privateKey as string)\n : null;\n lsSet(\"nonce\", null);\n }\n\n if (newState.accountId !== oldState.accountId) {\n events.notifyAccountListeners(newState.accountId as string);\n }\n\n if (\n (newState.hasOwnProperty(\"lastWalletId\") &&\n newState.lastWalletId !== oldState.lastWalletId) ||\n (newState.hasOwnProperty(\"accountId\") &&\n newState.accountId !== oldState.accountId) ||\n (newState.hasOwnProperty(\"privateKey\") &&\n newState.privateKey !== oldState.privateKey)\n ) {\n _adapter.setState(getWalletAdapterState());\n }\n}\n\nexport const updateTxHistory = (txStatus: TxStatus) => {\n const txId = txStatus.txId;\n _txHistory[txId] = {\n ...(_txHistory[txId] || {}),\n ...txStatus,\n updateTimestamp: Date.now(),\n };\n lsSet(\"txHistory\", _txHistory);\n events.notifyTxListeners(_txHistory[txId]);\n}\n\nexport const getConfig = (): NetworkConfig => {\n return _config;\n}\n\nexport const getTxHistory = (): TxHistory => {\n return _txHistory;\n}\n\n// Exposed \"write\" functions\nexport const setConfig = (newConf: NetworkConfig): void => {\n _config = { ...NETWORKS[newConf.networkId], ...newConf };\n lsSet(\"config\", _config);\n}\n\nexport const resetTxHistory = (): void => {\n _txHistory = {};\n lsSet(\"txHistory\", _txHistory);\n}\n","/**\n * @typedef {Object} WalletState\n * @property {string} [accountId] - NEAR account ID if signed in\n * @property {string} [publicKey] - Public key if available\n * @property {string} [privateKey] - Private key if available\n * @property {string} [lastWalletId] - ID of last used wallet\n * @property {string} [networkId] - ID of last used network\n */\n\n/**\n * @typedef {Object} SignInConfig\n * @property {string} networkId - NEAR network ID ('mainnet' or 'testnet')\n * @property {string} contractId - Contract ID to request access for\n * @property {string} [walletId] - Preferred wallet to use. E.g. 'near', 'here', 'meteor'\n * @property {string} [callbackUrl] - URL to redirect back to after wallet interaction\n */\n\n/**\n * @typedef {Object} SignInResult\n * @property {string} [url] - URL to redirect to if needed\n * @property {string} [accountId] - Account ID if immediately available\n * @property {string} [error] - Error message if sign in failed\n */\nexport interface SignInResult {\n url?: string;\n accountId?: string;\n error?: string;\n}\n\n/**\n * @typedef {Object} Transaction\n * @property {string} [signerId] - Transaction signer account ID\n * @property {string} receiverId - Transaction receiver account ID\n * @property {Object[]} actions - Transaction actions to perform\n */\n\n/**\n * @typedef {Object} TransactionConfig\n * @property {Transaction} transactions - Transaction actions to perform\n * @property {string} [callbackUrl] - URL to redirect back to after wallet interaction\n */\n\n/**\n * @typedef {Object} TransactionResult\n * @property {string} [url] - URL to redirect to if needed\n * @property {string} [hash] - Transaction hash if immediately available\n * @property {string} [error] - Error message if transaction failed\n * Represents the result of attempting to send or execute a transaction.\n */\nexport interface TransactionResult {\n /** URL to redirect to if needed. */\n url?: string;\n\n /** Transaction hash if immediately available. */\n hash?: string;\n\n /** Error message if the transaction failed. */\n error?: string;\n}\n\nexport interface WalletAdapterConstructor {\n widgetUrl?: string;\n targetOrigin?: string;\n onStateUpdate?: (state: any) => void;\n lastState?: any;\n callbackUrl?: string;\n}\n\n/**\n * @typedef {Object} WalletAdapterConfig\n * @property {string} [widgetUrl] - URL of the wallet widget (defaults to official hosted version)\n * @property {string} [targetOrigin] - Target origin for postMessage (defaults to '*')\n * @property {string} [lastState] - The last state that was given by WalletAdapter before the redirect or reload.\n * @property {(state: WalletState) => void} [onStateUpdate] - Called when wallet state changes\n * @property {string} [callbackUrl] - Default callback URL for wallet interactions (defaults to current page URL)\n */\n\n/**\n * Interface for interacting with NEAR wallets\n */\nexport class WalletAdapter {\n /** @type {HTMLIFrameElement} */\n #iframe: HTMLIFrameElement | null = null;\n\n /** @type {string} */\n #targetOrigin;\n\n /** @type {string} */\n #widgetUrl;\n\n /** @type {Map} */\n #pending = new Map();\n\n /** @type {WalletState} */\n #state;\n\n /** @type {Function} */\n #onStateUpdate;\n\n /** @type {string} */\n #callbackUrl;\n\n /** @type {string} */\n static defaultWidgetUrl = \"https://wallet-adapter.fastnear.com\";\n\n /**\n * @param {WalletAdapterConfig} [config]\n */\n constructor({\n widgetUrl = WalletAdapter.defaultWidgetUrl,\n targetOrigin = \"*\",\n onStateUpdate,\n lastState,\n callbackUrl = window.location.href,\n }: WalletAdapterConstructor = {}) {\n this.#targetOrigin = targetOrigin;\n this.#widgetUrl = widgetUrl;\n this.#onStateUpdate = onStateUpdate;\n this.#callbackUrl = callbackUrl;\n this.#state = lastState || {};\n window.addEventListener(\"message\", this.#handleMessage.bind(this));\n }\n\n /**\n * Creates an iframe for wallet interaction\n * @param {string} path - Path to load in iframe\n * @returns {HTMLIFrameElement}\n */\n #createIframe(path) {\n // Remove existing iframe if any\n if (this.#iframe) {\n this.#iframe.remove();\n }\n\n // Create URL\n const url = new URL(path, this.#widgetUrl);\n\n // Create and configure iframe\n const iframe = document.createElement(\"iframe\");\n iframe.src = url.toString();\n iframe.allow = \"usb\";\n iframe.style.border = \"none\";\n iframe.style.zIndex = \"10000\";\n iframe.style.position = \"fixed\";\n iframe.style.display = \"block\";\n iframe.style.top = \"0\";\n iframe.style.left = \"0\";\n iframe.style.width = \"100%\";\n iframe.style.height = \"100%\";\n document.body.appendChild(iframe);\n\n this.#iframe = iframe;\n return iframe;\n }\n\n /**\n * Handles messages from the wallet widget\n * @param {MessageEvent} event\n */\n #handleMessage(event) {\n // Check origin if specified\n if (this.#targetOrigin !== \"*\" && event.origin !== this.#targetOrigin) {\n return;\n }\n\n const { id, type, action, payload } = event.data;\n if (type !== \"wallet-adapter\") return;\n\n // Handle close action\n if (action === \"close\") {\n this.#iframe?.remove();\n this.#iframe = null;\n return;\n }\n\n // Update state if provided\n if (payload?.state) {\n this.#state = { ...this.#state, ...payload.state };\n this.#onStateUpdate?.(this.#state);\n }\n\n // Resolve pending promise if any\n const resolve = this.#pending.get(id) as ((value: SignInResult) => void);\n if (resolve) {\n this.#pending.delete(id);\n this.#iframe?.remove();\n this.#iframe = null;\n resolve(payload as SignInResult);\n }\n }\n\n /**\n * Sends a message to the wallet widget\n * @param {string} path - Path to load in iframe\n * @param {string} method - Method to call\n * @param {Object} params - Parameters to pass\n * @returns {Promise}\n */\n async #sendMessage(path, method, params): Promise {\n return new Promise((resolve) => {\n const id = Math.random().toString(36).slice(2);\n this.#pending.set(id, resolve);\n\n const iframe = this.#createIframe(path);\n\n iframe.onload = () => {\n iframe.contentWindow?.postMessage(\n {\n type: \"wallet-adapter\",\n method,\n params: {\n id,\n ...params,\n state: this.#state,\n callbackUrl: params.callbackUrl || this.#callbackUrl,\n },\n },\n this.#targetOrigin\n );\n };\n });\n }\n\n /**\n * Get current wallet state\n * @returns {WalletState}\n */\n getState() {\n return { ...this.#state };\n }\n\n /**\n * Set current wallet state\n * @param state\n */\n setState(state) {\n this.#state = state;\n }\n\n /**\n * Sign in with a NEAR wallet\n * @param {SignInConfig} config\n * @returns {Promise}\n *\n * Should be returning SignInResult\n */\n async signIn(config): Promise {\n return this.#sendMessage(\"/login.html\", \"signIn\", config);\n }\n\n /**\n * Send a transaction using connected wallet\n * @param {TransactionConfig} config\n * @returns {Promise}\n */\n async sendTransactions(config): Promise {\n return this.#sendMessage(\"/send.html\", \"sendTransactions\", config);\n }\n\n /**\n * Clean up adapter resources\n */\n destroy() {\n window.removeEventListener(\"message\", this.#handleMessage);\n this.#iframe?.remove();\n this.#iframe = null;\n }\n}\n","import Big from \"big.js\";\nimport {\n lsSet,\n lsGet,\n tryParseJson,\n fromBase64,\n toBase64,\n canSignWithLAK,\n toBase58,\n parseJsonFromBytes,\n signHash,\n publicKeyFromPrivate,\n privateKeyFromRandom,\n serializeTransaction,\n serializeSignedTransaction, bytesToBase64, PlainTransaction,\n} from \"@fastnear/utils\";\n\nimport {\n _adapter,\n _state,\n DEFAULT_NETWORK_ID,\n NETWORKS,\n getTxHistory,\n update,\n updateTxHistory,\n} from \"./state.js\";\n\nimport {\n getConfig,\n setConfig,\n resetTxHistory,\n} from \"./state.js\";\n\nimport { sha256 } from \"@noble/hashes/sha2\";\nimport * as reExportAllUtils from \"@fastnear/utils\";\nimport * as stateExports from \"./state.js\";\n\nBig.DP = 27;\nexport const MaxBlockDelayMs = 1000 * 60 * 60 * 6; // 6 hours\n\nexport interface AccessKeyWithError {\n result: {\n nonce: number;\n permission?: any;\n error?: string;\n }\n}\n\nexport interface WalletTxResult {\n url?: string;\n outcomes?: Array<{ transaction: { hash: string } }>;\n rejected?: boolean;\n error?: string;\n}\n\nexport interface BlockView {\n result: {\n header: {\n hash: string;\n timestamp_nanosec: string;\n }\n }\n}\n\n// The structure it's saved to in storage\nexport interface LastKnownBlock {\n header: {\n hash: string;\n timestamp_nanosec: string;\n }\n}\n\nexport function withBlockId(params: Record, blockId?: string) {\n if (blockId === \"final\" || blockId === \"optimistic\") {\n return { ...params, finality: blockId };\n }\n return blockId ? { ...params, block_id: blockId } : { ...params, finality: \"optimistic\" };\n}\n\nexport async function sendRpc(method: string, params: Record | any[]) {\n const config = getConfig();\n if (!config?.nodeUrl) {\n throw new Error(\"fastnear: getConfig() returned invalid config: missing nodeUrl.\");\n }\n const response = await fetch(config.nodeUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: `fastnear-${Date.now()}`,\n method,\n params,\n }),\n });\n const result = await response.json();\n if (result.error) {\n throw new Error(JSON.stringify(result.error));\n }\n return result;\n}\n\nexport function afterTxSent(txId: string) {\n const txHistory = getTxHistory();\n sendRpc(\"tx\", {\n tx_hash: txHistory[txId]?.txHash,\n sender_account_id: txHistory[txId]?.tx?.signerId,\n wait_until: \"EXECUTED_OPTIMISTIC\",\n })\n .then( result => {\n const successValue = result?.result?.status?.SuccessValue;\n updateTxHistory({\n txId,\n status: \"Executed\",\n result,\n successValue: successValue ? tryParseJson(fromBase64(successValue)) : undefined,\n finalState: true,\n });\n })\n .catch((error) => {\n updateTxHistory({\n txId,\n status: \"ErrorAfterIncluded\",\n error: tryParseJson(error.message) ?? error.message,\n finalState: true,\n });\n });\n}\n\nexport async function sendTxToRpc(signedTxBase64: string, waitUntil: string | undefined, txId: string) {\n // default to \"INCLUDED\"\n // see options: https://docs.near.org/api/rpc/transactions#tx-status-result\n waitUntil = waitUntil || \"INCLUDED\";\n\n try {\n const sendTxRes = await sendRpc(\"send_tx\", {\n signed_tx_base64: signedTxBase64,\n wait_until: waitUntil,\n });\n\n updateTxHistory({ txId, status: \"Included\", finalState: false });\n afterTxSent(txId);\n\n return sendTxRes;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : \"Unknown error\";\n updateTxHistory({\n txId,\n status: \"Error\",\n error: tryParseJson(errorMessage) ?? errorMessage,\n finalState: false,\n });\n throw new Error(errorMessage);\n }\n}\n\nexport interface AccessKeyView {\n nonce: number;\n permission: any;\n}\n\n/**\n * Generates a mock transaction ID.\n *\n * This function creates a pseudo-unique transaction ID for testing or\n * non-production use. It combines the current timestamp with a\n * random component for uniqueness.\n *\n * **Note:** This is not cryptographically secure and should not be used\n * for actual transaction processing.\n *\n * @returns {string} A mock transaction ID in the format `tx-{timestamp}-{random}`\n */\nexport function generateTxId(): string {\n const randomPart = crypto.getRandomValues(new Uint32Array(2)).join(\"\");\n return `tx-${Date.now()}-${parseInt(randomPart, 10).toString(36)}`;\n}\n\nexport const accountId = () => _state.accountId;\nexport const publicKey = () => _state.publicKey;\n\nexport const config = (newConfig?: Record) => {\n const current = getConfig();\n if (newConfig) {\n if (newConfig.networkId && current.networkId !== newConfig.networkId) {\n setConfig(newConfig.networkId);\n update({ accountId: null, privateKey: null, lastWalletId: null });\n lsSet(\"block\", null);\n resetTxHistory();\n }\n setConfig({ ...getConfig(), ...newConfig });\n }\n return getConfig();\n};\n\nexport const authStatus = (): string | Record => {\n if (!_state.accountId) {\n return \"SignedOut\";\n }\n return \"SignedIn\";\n};\n\n// this is an intentional stub\n// and it's probably partially done, to help ease future features\n// for now we'll assume each web end user has one keypair in storage\n// for every contract they wish to interact with\n// later, it may be prudent to hold multiple, but until then this function\n// just returns the access key as if it were among others in the array.\n// we're pretending like we really thought about which access key we're returning\n// based on the opts argument. this allows us to fill this logic in later.\nexport const getPublicKeyForContract = (opts?: any) => {\n return publicKey();\n}\n\n// returns details on the selected:\n// network, wallet, and explorer details as well as\n// sending account, contract, and selected public key\nexport const selected = () => {\n const network = getConfig().networkId;\n const nodeUrl = getConfig().nodeUrl;\n const walletUrl = getConfig().walletUrl;\n const helperUrl = getConfig().helperUrl;\n const explorerUrl = getConfig().explorerUrl;\n\n const account = accountId();\n const contract = _state.accessKeyContractId;\n const publicKey = getPublicKeyForContract();\n\n return {\n network,\n nodeUrl,\n walletUrl,\n helperUrl,\n explorerUrl,\n account,\n contract,\n publicKey\n }\n}\n\nexport const requestSignIn = async ({ contractId }: { contractId: string }) => {\n const privateKey = privateKeyFromRandom();\n update({ accessKeyContractId: contractId, accountId: null, privateKey });\n const pubKey = publicKeyFromPrivate(privateKey);\n\n const result = await _adapter.signIn({\n networkId: getConfig().networkId,\n contractId,\n publicKey: pubKey,\n });\n\n if (result.error) {\n throw new Error(`Wallet error: ${result.error}`);\n }\n if (result.url) {\n if (typeof window !== \"undefined\") {\n setTimeout(() => {\n window.location.href = result.url;\n }, 100);\n }\n } else if (result.accountId) {\n update({ accountId: result.accountId });\n }\n};\n\nexport const view = async ({\n contractId,\n methodName,\n args,\n argsBase64,\n blockId,\n }: {\n contractId: string;\n methodName: string;\n args?: any;\n argsBase64?: string;\n blockId?: string;\n}) => {\n const encodedArgs = argsBase64 || (args ? toBase64(JSON.stringify(args)) : \"\");\n const queryResult = await sendRpc(\n \"query\",\n withBlockId(\n {\n request_type: \"call_function\",\n account_id: contractId,\n method_name: methodName,\n args_base64: encodedArgs,\n },\n blockId\n )\n );\n\n return parseJsonFromBytes(queryResult.result.result);\n};\n\nexport const queryAccount = async ({\n accountId,\n blockId,\n }: {\n accountId: string;\n blockId?: string;\n}) => {\n return sendRpc(\n \"query\",\n withBlockId({ request_type: \"view_account\", account_id: accountId }, blockId)\n );\n};\n\nexport const queryBlock = async ({ blockId }: { blockId?: string }): Promise => {\n return sendRpc(\"block\", withBlockId({}, blockId));\n};\n\nexport const queryAccessKey = async ({\n accountId,\n publicKey,\n blockId,\n }: {\n accountId: string;\n publicKey: string;\n blockId?: string;\n}): Promise => {\n return sendRpc(\n \"query\",\n withBlockId(\n { request_type: \"view_access_key\", account_id: accountId, public_key: publicKey },\n blockId\n )\n );\n};\n\nexport const queryTx = async ({ txHash, accountId }: { txHash: string; accountId: string }) => {\n return sendRpc(\"tx\", [txHash, accountId]);\n};\n\nexport const localTxHistory = () => {\n return getTxHistory();\n};\n\nexport const signOut = () => {\n update({ accountId: null, privateKey: null, contractId: null });\n setConfig(NETWORKS[DEFAULT_NETWORK_ID]);\n};\n\nexport const sendTx = async ({\n receiverId,\n actions,\n waitUntil,\n }: {\n receiverId: string;\n actions: any[];\n waitUntil?: string;\n}) => {\n const signerId = _state.accountId;\n if (!signerId) throw new Error(\"Must sign in\");\n\n const publicKey = _state.publicKey ?? \"\";\n const privKey = _state.privateKey;\n // this generates a mock transaction ID so we can keep track of each tx\n const txId = generateTxId();\n\n if (!privKey || receiverId !== _state.accessKeyContractId || !canSignWithLAK(actions)) {\n const jsonTx = { signerId, receiverId, actions };\n updateTxHistory({ status: \"Pending\", txId, tx: jsonTx, finalState: false });\n\n const url = new URL(typeof window !== \"undefined\" ? window.location.href : \"\");\n url.searchParams.set(\"txIds\", txId);\n\n // preserve existing url params\n const existingParams = new URLSearchParams(window.location.search);\n existingParams.forEach((value, key) => {\n if (!url.searchParams.has(key)) {\n url.searchParams.set(key, value);\n }\n });\n\n // we're wanting to preserve URL params that we send in\n // but make sure we're not feeding back error params\n // from a previous failure\n\n url.searchParams.delete(\"errorCode\");\n url.searchParams.delete(\"errorMessage\");\n\n try {\n const result: WalletTxResult = await _adapter.sendTransactions({\n transactions: [jsonTx],\n callbackUrl: url.toString(),\n });\n\n if (result.url) {\n if (typeof window !== \"undefined\") {\n setTimeout(() => {\n window.location.href = result.url!;\n }, 100);\n }\n } else if (result.outcomes?.length) {\n result.outcomes.forEach((r) =>\n updateTxHistory({\n txId,\n status: \"Executed\",\n result: r,\n txHash: r.transaction.hash,\n finalState: true,\n })\n );\n } else if (result.rejected) {\n updateTxHistory({ txId, status: \"RejectedByUser\", finalState: true });\n } else if (result.error) {\n updateTxHistory({\n txId,\n status: \"Error\",\n error: tryParseJson(result.error),\n finalState: true,\n });\n }\n\n return result;\n } catch (err) {\n console.error('fastnear: error sending tx using adapter:', err)\n updateTxHistory({\n txId,\n status: \"Error\",\n error: tryParseJson((err as Error).message),\n finalState: true,\n });\n\n return Promise.reject(err);\n }\n }\n\n let nonce = lsGet(\"nonce\") as number | null;\n if (nonce == null) {\n const accessKey = await queryAccessKey({ accountId: signerId, publicKey: publicKey });\n if (accessKey.result.error) {\n throw new Error(`Access key error: ${accessKey.result.error} when attempting to get nonce for ${signerId} for public key ${publicKey}`);\n }\n nonce = accessKey.result.nonce;\n lsSet(\"nonce\", nonce);\n }\n\n let lastKnownBlock = lsGet(\"block\") as LastKnownBlock | null;\n if (\n !lastKnownBlock ||\n parseFloat(lastKnownBlock.header.timestamp_nanosec) / 1e6 + MaxBlockDelayMs < Date.now()\n ) {\n const latestBlock = await queryBlock({ blockId: \"final\" });\n lastKnownBlock = {\n header: {\n hash: latestBlock.result.header.hash,\n timestamp_nanosec: latestBlock.result.header.timestamp_nanosec,\n },\n };\n lsSet(\"block\", lastKnownBlock);\n }\n\n nonce += 1;\n lsSet(\"nonce\", nonce);\n\n const blockHash = lastKnownBlock.header.hash;\n\n const plainTransactionObj: PlainTransaction = {\n signerId,\n publicKey,\n nonce,\n receiverId,\n blockHash,\n actions,\n };\n\n const txBytes = serializeTransaction(plainTransactionObj);\n const txHashBytes = sha256(txBytes);\n const txHash58 = toBase58(txHashBytes);\n\n const signatureBase58 = signHash(txHashBytes, privKey, { returnBase58: true });\n const signedTransactionBytes = serializeSignedTransaction(plainTransactionObj, signatureBase58);\n const signedTxBase64 = bytesToBase64(signedTransactionBytes);\n\n updateTxHistory({\n status: \"Pending\",\n txId,\n tx: plainTransactionObj,\n signature: signatureBase58,\n signedTxBase64,\n txHash: txHash58,\n finalState: false,\n });\n\n try {\n return await sendTxToRpc(signedTxBase64, waitUntil, txId);\n } catch (error) {\n console.error(\"Error Sending Transaction:\", error, plainTransactionObj, signedTxBase64);\n }\n};\n\n// exports\nexport const exp = {\n utils: {}, // we will map this in a moment, giving keys, for IDE hints\n borsh: reExportAllUtils.exp.borsh,\n borshSchema: reExportAllUtils.exp.borshSchema.getBorshSchema(),\n};\n\nfor (const key in reExportAllUtils) {\n exp.utils[key] = reExportAllUtils[key];\n}\n\n// devx\nexport const utils = exp.utils;\n\nexport const state = {}\n\nfor (const key in stateExports) {\n state[key] = stateExports[key];\n}\n\n// devx\n\nexport const event = state['events'];\ndelete state['events'];\n\n// Wallet redirect handling\ntry {\n if (typeof window !== \"undefined\") {\n const url = new URL(window.location.href);\n const accId = url.searchParams.get(\"account_id\");\n const pubKey = url.searchParams.get(\"public_key\");\n const errCode = url.searchParams.get(\"errorCode\");\n const errMsg = url.searchParams.get(\"errorMessage\");\n const decodedErrMsg = errMsg ? decodeURIComponent(errMsg) : null;\n\n const txHashes = url.searchParams.get(\"transactionHashes\");\n const txIds = url.searchParams.get(\"txIds\");\n\n if (errCode || errMsg) {\n console.warn(new Error(`Wallet raises:\\ncode: ${errCode}\\nmessage: ${decodedErrMsg}`));\n }\n\n if (accId && pubKey) {\n if (pubKey === _state.publicKey) {\n update({ accountId: accId });\n } else {\n // it's possible the end user has a URL param that's old. we'll remove the public_key param\n // if logged out, no need to throw warning\n if (authStatus() === \"SignedIn\") {\n console.warn(\"Public key mismatch from wallet redirect\", pubKey, _state.publicKey);\n }\n url.searchParams.delete(\"public_key\");\n }\n }\n\n if (txHashes || txIds) {\n const hashArr = txHashes ? txHashes.split(\",\") : [];\n const idArr = txIds ? txIds.split(\",\") : [];\n if (idArr.length > hashArr.length) {\n idArr.forEach((id) => {\n updateTxHistory({ txId: id, status: \"RejectedByUser\", finalState: true });\n });\n } else if (idArr.length === hashArr.length) {\n idArr.forEach((id, i) => {\n updateTxHistory({\n txId: id,\n status: \"PendingGotTxHash\",\n txHash: hashArr[i],\n finalState: false,\n });\n afterTxSent(id);\n });\n } else {\n console.error(new Error(\"Transaction hash mismatch from wallet redirect\"), idArr, hashArr);\n }\n }\n\n // we can consider removing these, but want to be careful because\n // it can be helpful for a dev to have a URL they can debug with\n // we won't want to remove information\n\n // pretty sure txIds can go, especially if you can tell it's been more than 5 minutes or something\n // public_key sometimes confuses it, so this might only be needed when adding a new access key\n // and perhaps once we've confirmed that the transaction hashes are getting saved to storage\n // (not sure about that section of code) then we can get rid of the transactionHashes, too\n\n url.searchParams.delete(\"txIds\");\n if (authStatus() === \"SignedOut\") {\n url.searchParams.delete(\"errorCode\");\n url.searchParams.delete(\"errorMessage\");\n }\n // ^ we've decided these ones make sense to keep\n\n // I'd like to keep this for posterity. for a bit.\n // url.searchParams.delete(\"account_id\");\n // url.searchParams.delete(\"public_key\");\n\n // url.searchParams.delete(\"all_keys\");\n // url.searchParams.delete(\"transactionHashes\");\n // window.history.replaceState({}, \"\", url.toString());\n }\n} catch (e) {\n console.error(\"Error handling wallet redirect:\", e);\n}\n\n// action helpers\nexport const actions = {\n functionCall: ({\n methodName,\n gas,\n deposit,\n args,\n argsBase64,\n }: {\n methodName: string;\n gas?: string;\n deposit?: string;\n args?: Record;\n argsBase64?: string;\n }) => ({\n type: \"FunctionCall\",\n methodName,\n args,\n argsBase64,\n gas,\n deposit,\n }),\n\n transfer: (yoctoAmount: string) => ({\n type: \"Transfer\",\n deposit: yoctoAmount,\n }),\n\n stakeNEAR: ({amount, publicKey}: { amount: string; publicKey: string }) => ({\n type: \"Stake\",\n stake: amount,\n publicKey,\n }),\n\n addFullAccessKey: ({publicKey}: { publicKey: string }) => ({\n type: \"AddKey\",\n publicKey: publicKey,\n accessKey: {permission: \"FullAccess\"},\n }),\n\n addLimitedAccessKey: ({\n publicKey,\n allowance,\n accountId,\n methodNames,\n }: {\n publicKey: string;\n allowance: string;\n accountId: string;\n methodNames: string[];\n }) => ({\n type: \"AddKey\",\n publicKey: publicKey,\n accessKey: {\n permission: \"FunctionCall\",\n allowance,\n receiverId: accountId,\n methodNames,\n },\n }),\n\n deleteKey: ({publicKey}: { publicKey: string }) => ({\n type: \"DeleteKey\",\n publicKey,\n }),\n\n deleteAccount: ({beneficiaryId}: { beneficiaryId: string }) => ({\n type: \"DeleteAccount\",\n beneficiaryId,\n }),\n\n createAccount: () => ({\n type: \"CreateAccount\",\n }),\n\n deployContract: ({codeBase64}: { codeBase64: string }) => ({\n type: \"DeployContract\",\n codeBase64,\n }),\n};\n"],"mappings":"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","names":["src_exports","exp","Big","src_exports","crypto","crypto","view","_32n","state","view","isBytes","abytes","abytes","isBytes","abytes","isBytes","_0n","_1n","_2n","P","Fp","bitLen","_0n","_1n","_0n","_1n","P","window","wbits","_0n","_1n","_2n","_8n","Fp","randomBytes","uvRatio","adjustScalarBytes","G","A","B","F","C","D","E","H","X3","Y3","T3","Z3","cofactor","publicKey","utils","_0n","_1n","_2n","_3n","_5n","_8n","P","pow","_8n","view","e","actions","publicKey","EncodeBuffer","DecodeBuffer","d","b","ErrorSchema","BorshSerializer","BorshDeserializer","event","state","config","state","accountId","config","publicKey","accountId","actions","exp","src_exports"]} \ No newline at end of file diff --git a/static/ru/agents.md b/static/ru/agents.md index 1acbaf4..41f6435 100644 --- a/static/ru/agents.md +++ b/static/ru/agents.md @@ -17,6 +17,7 @@ - Используйте индексированные API, когда пользователю нужен ответ в продуктовой форме — балансы, активы, история аккаунта или история переводов. - Используйте [Справочник RPC](https://docs.fastnear.com/ru/rpc), когда пользователю нужны канонические поля на уровне протокола, вызовы контрактов или отправка транзакций. +- Если вы используете размещённый JS-рантайм на [js.fastnear.com](https://js.fastnear.com), начинайте с низкоуровневых методов вроде `near.view`, `near.queryAccount` и `near.tx.*`, а к `near.recipes.*` обращайтесь только тогда, когда task helper действительно является самым коротким путём к ответу. - Используйте [NEAR Data API](https://docs.fastnear.com/ru/neardata), когда вопрос касается свежих оптимистичных или финализированных блоков и явного опроса. - Используйте [Снапшоты](https://docs.fastnear.com/ru/snapshots) для операторских сценариев, а не для чтения прикладных данных. - Один API-ключ FastNear работает и для RPC, и для API-эндпоинтов. @@ -90,20 +91,24 @@ ## Аутентифицируйтесь один раз, используйте везде -Публичные эндпоинты часто работают и без ключа. Добавьте ключ, если нужны повышенные лимиты, единая аутентифицированная модель или платные сценарии. Один и тот же ключ работает со всеми API FastNear выше, включая обычные и архивные RPC-хосты; передавайте его либо в HTTP-заголовке, либо в URL-параметре: +Начните с API-ключа FastNear и используйте его во всех API FastNear выше, включая обычные и архивные RPC-хосты. Передавайте его либо в HTTP-заголовке, либо в URL-параметре: ```bash title="Заголовок Authorization" +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + curl "https://rpc.mainnet.fastnear.com" \ - -H "Authorization: Bearer ${API_KEY}" \ + -H "Authorization: Bearer $FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` ```bash title="URL-параметр" -curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + +curl "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" ``` -Получить ключ: [dashboard.fastnear.com](https://dashboard.fastnear.com). Операционный режим для неинтерактивных сред: [Аутентификация для агентов](https://docs.fastnear.com/ru/agents/auth) — ключи должны жить в переменных окружения или менеджере секретов, а не в браузерном хранилище, логах чатов или промптах. Полный сценарий и детали заголовков: [Аутентификация и доступ](https://docs.fastnear.com/ru/auth). +Получите API-ключ в [FastNear Dashboard](https://dashboard.fastnear.com). Операционный режим для неинтерактивных сред: [Аутентификация для агентов](https://docs.fastnear.com/ru/agents/auth) — ключи должны жить в переменных окружения или менеджере секретов, а не в браузерном хранилище, логах чатов или промптах. Полный сценарий и детали заголовков: [Аутентификация и доступ](https://docs.fastnear.com/ru/auth). ## Как вынимать чистую документацию в промпт @@ -137,3 +142,10 @@ curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" - Нужна глубина маршрутизации и компромиссы? [Как выбрать подходящую поверхность](https://docs.fastnear.com/ru/agents/choosing-surfaces) - Нужен режим работы с учётными данными и обращение с секретами? [Аутентификация для агентов](https://docs.fastnear.com/ru/agents/auth) - Нужны примеры сценариев? [Плейбуки для агентов](https://docs.fastnear.com/ru/agents/playbooks) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/agents/auth.md b/static/ru/agents/auth.md index 3ddae5d..073ed0b 100644 --- a/static/ru/agents/auth.md +++ b/static/ru/agents/auth.md @@ -4,7 +4,7 @@ Агенты должны аутентифицироваться в FastNear так же, как это делают продовые бэкенды. Не переносите браузерно-демонстрационный режим из UI документации в агента, воркера или среду автоматизации. -Один API-ключ FastNear работает во всех RPC и API-эндпоинтах. Многие публичные чтения работают и без ключа. Для агента важнее не само наличие аутентификации, а где живёт учётная запись, как она прикрепляется к запросам и как не допустить её утечки в промпты, логи или состояние браузера. +Один API-ключ FastNear работает во всех RPC и API-эндпоинтах. Для агента важнее не само наличие аутентификации, а где живёт учётная запись, как она прикрепляется к запросам и как не допустить её утечки в промпты, логи или состояние браузера. ## Если нужно только правило @@ -28,8 +28,8 @@ | Способ | Используйте, когда... | Заметки | | --- | --- | --- | -| `Authorization: Bearer ${API_KEY}` | HTTP-клиентом или бэкендом управляете вы | Лучшее значение по умолчанию для агентов. Меньше шансов утечь в логи URL, аналитику или скопированные ссылки. | -| `?apiKey=${API_KEY}` | используется простой curl или система, которой сложно выставлять заголовки | Тоже допустимо, но URL обычно дальше путешествуют через логи и инструменты. Применяйте осознанно. | +| `Authorization: Bearer ${FASTNEAR_API_KEY}` | HTTP-клиентом или бэкендом управляете вы | Лучшее значение по умолчанию для агентов. Меньше шансов утечь в логи URL, аналитику или скопированные ссылки. | +| `?apiKey=${FASTNEAR_API_KEY}` | используется простой curl или система, которой сложно выставлять заголовки | Тоже допустимо, но URL обычно дальше путешествуют через логи и инструменты. Применяйте осознанно. | Если есть выбор — используйте заголовочную форму. @@ -60,13 +60,13 @@ const response = await fetch('https://rpc.mainnet.fastnear.com', { }); ``` -## Когда аутентификации не хватает +## Если в среде выполнения нет ключа -Многие публичные эндпоинты FastNear по-прежнему доступны на чтение без ключа. Если агент может ответить на вопрос пользователя через публичный трафик — делайте так. +Агенту по умолчанию стоит стартовать с настроенным API-ключом FastNear. Некоторые публичные чтения могут сработать и без него, но это не должно быть базовой рабочей моделью. -Когда ключ нужен для повышенных лимитов, платного доступа или аутентифицированного трафика: +Если в настроенной среде ключа пока нет: -- подскажите пользователю создать или забрать ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com) +- подскажите пользователю создать или забрать ключ в [FastNear Dashboard](https://dashboard.fastnear.com) - попросите настроить его в переменной окружения, менеджере секретов или конфигурации бэкенда - не просите вставлять сырой ключ в чат, чтобы агент «носил» его с собой @@ -93,3 +93,10 @@ const response = await fetch('https://rpc.mainnet.fastnear.com', { - [Аутентификация и доступ](https://docs.fastnear.com/ru/auth) - [Агенты на FastNear](https://docs.fastnear.com/ru/agents) - [Как выбрать подходящую поверхность](https://docs.fastnear.com/ru/agents/choosing-surfaces) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/agents/auth/index.md b/static/ru/agents/auth/index.md index 3ddae5d..073ed0b 100644 --- a/static/ru/agents/auth/index.md +++ b/static/ru/agents/auth/index.md @@ -4,7 +4,7 @@ Агенты должны аутентифицироваться в FastNear так же, как это делают продовые бэкенды. Не переносите браузерно-демонстрационный режим из UI документации в агента, воркера или среду автоматизации. -Один API-ключ FastNear работает во всех RPC и API-эндпоинтах. Многие публичные чтения работают и без ключа. Для агента важнее не само наличие аутентификации, а где живёт учётная запись, как она прикрепляется к запросам и как не допустить её утечки в промпты, логи или состояние браузера. +Один API-ключ FastNear работает во всех RPC и API-эндпоинтах. Для агента важнее не само наличие аутентификации, а где живёт учётная запись, как она прикрепляется к запросам и как не допустить её утечки в промпты, логи или состояние браузера. ## Если нужно только правило @@ -28,8 +28,8 @@ | Способ | Используйте, когда... | Заметки | | --- | --- | --- | -| `Authorization: Bearer ${API_KEY}` | HTTP-клиентом или бэкендом управляете вы | Лучшее значение по умолчанию для агентов. Меньше шансов утечь в логи URL, аналитику или скопированные ссылки. | -| `?apiKey=${API_KEY}` | используется простой curl или система, которой сложно выставлять заголовки | Тоже допустимо, но URL обычно дальше путешествуют через логи и инструменты. Применяйте осознанно. | +| `Authorization: Bearer ${FASTNEAR_API_KEY}` | HTTP-клиентом или бэкендом управляете вы | Лучшее значение по умолчанию для агентов. Меньше шансов утечь в логи URL, аналитику или скопированные ссылки. | +| `?apiKey=${FASTNEAR_API_KEY}` | используется простой curl или система, которой сложно выставлять заголовки | Тоже допустимо, но URL обычно дальше путешествуют через логи и инструменты. Применяйте осознанно. | Если есть выбор — используйте заголовочную форму. @@ -60,13 +60,13 @@ const response = await fetch('https://rpc.mainnet.fastnear.com', { }); ``` -## Когда аутентификации не хватает +## Если в среде выполнения нет ключа -Многие публичные эндпоинты FastNear по-прежнему доступны на чтение без ключа. Если агент может ответить на вопрос пользователя через публичный трафик — делайте так. +Агенту по умолчанию стоит стартовать с настроенным API-ключом FastNear. Некоторые публичные чтения могут сработать и без него, но это не должно быть базовой рабочей моделью. -Когда ключ нужен для повышенных лимитов, платного доступа или аутентифицированного трафика: +Если в настроенной среде ключа пока нет: -- подскажите пользователю создать или забрать ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com) +- подскажите пользователю создать или забрать ключ в [FastNear Dashboard](https://dashboard.fastnear.com) - попросите настроить его в переменной окружения, менеджере секретов или конфигурации бэкенда - не просите вставлять сырой ключ в чат, чтобы агент «носил» его с собой @@ -93,3 +93,10 @@ const response = await fetch('https://rpc.mainnet.fastnear.com', { - [Аутентификация и доступ](https://docs.fastnear.com/ru/auth) - [Агенты на FastNear](https://docs.fastnear.com/ru/agents) - [Как выбрать подходящую поверхность](https://docs.fastnear.com/ru/agents/choosing-surfaces) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/agents/choosing-surfaces.md b/static/ru/agents/choosing-surfaces.md index f78d329..0e21fa4 100644 --- a/static/ru/agents/choosing-surfaces.md +++ b/static/ru/agents/choosing-surfaces.md @@ -255,3 +255,10 @@ - [Агенты на FastNear](https://docs.fastnear.com/ru/agents) — полная карта поверхностей, базовые URL и подсказки по поглощению промптов. - [Аутентификация для агентов](https://docs.fastnear.com/ru/agents/auth) — работа с учётными данными и операционный режим. - [Плейбуки для агентов](https://docs.fastnear.com/ru/agents/playbooks) — примеры многошаговых сценариев. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/agents/choosing-surfaces/index.md b/static/ru/agents/choosing-surfaces/index.md index f78d329..0e21fa4 100644 --- a/static/ru/agents/choosing-surfaces/index.md +++ b/static/ru/agents/choosing-surfaces/index.md @@ -255,3 +255,10 @@ - [Агенты на FastNear](https://docs.fastnear.com/ru/agents) — полная карта поверхностей, базовые URL и подсказки по поглощению промптов. - [Аутентификация для агентов](https://docs.fastnear.com/ru/agents/auth) — работа с учётными данными и операционный режим. - [Плейбуки для агентов](https://docs.fastnear.com/ru/agents/playbooks) — примеры многошаговых сценариев. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/agents/index.md b/static/ru/agents/index.md index 1acbaf4..41f6435 100644 --- a/static/ru/agents/index.md +++ b/static/ru/agents/index.md @@ -17,6 +17,7 @@ - Используйте индексированные API, когда пользователю нужен ответ в продуктовой форме — балансы, активы, история аккаунта или история переводов. - Используйте [Справочник RPC](https://docs.fastnear.com/ru/rpc), когда пользователю нужны канонические поля на уровне протокола, вызовы контрактов или отправка транзакций. +- Если вы используете размещённый JS-рантайм на [js.fastnear.com](https://js.fastnear.com), начинайте с низкоуровневых методов вроде `near.view`, `near.queryAccount` и `near.tx.*`, а к `near.recipes.*` обращайтесь только тогда, когда task helper действительно является самым коротким путём к ответу. - Используйте [NEAR Data API](https://docs.fastnear.com/ru/neardata), когда вопрос касается свежих оптимистичных или финализированных блоков и явного опроса. - Используйте [Снапшоты](https://docs.fastnear.com/ru/snapshots) для операторских сценариев, а не для чтения прикладных данных. - Один API-ключ FastNear работает и для RPC, и для API-эндпоинтов. @@ -90,20 +91,24 @@ ## Аутентифицируйтесь один раз, используйте везде -Публичные эндпоинты часто работают и без ключа. Добавьте ключ, если нужны повышенные лимиты, единая аутентифицированная модель или платные сценарии. Один и тот же ключ работает со всеми API FastNear выше, включая обычные и архивные RPC-хосты; передавайте его либо в HTTP-заголовке, либо в URL-параметре: +Начните с API-ключа FastNear и используйте его во всех API FastNear выше, включая обычные и архивные RPC-хосты. Передавайте его либо в HTTP-заголовке, либо в URL-параметре: ```bash title="Заголовок Authorization" +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + curl "https://rpc.mainnet.fastnear.com" \ - -H "Authorization: Bearer ${API_KEY}" \ + -H "Authorization: Bearer $FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` ```bash title="URL-параметр" -curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + +curl "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" ``` -Получить ключ: [dashboard.fastnear.com](https://dashboard.fastnear.com). Операционный режим для неинтерактивных сред: [Аутентификация для агентов](https://docs.fastnear.com/ru/agents/auth) — ключи должны жить в переменных окружения или менеджере секретов, а не в браузерном хранилище, логах чатов или промптах. Полный сценарий и детали заголовков: [Аутентификация и доступ](https://docs.fastnear.com/ru/auth). +Получите API-ключ в [FastNear Dashboard](https://dashboard.fastnear.com). Операционный режим для неинтерактивных сред: [Аутентификация для агентов](https://docs.fastnear.com/ru/agents/auth) — ключи должны жить в переменных окружения или менеджере секретов, а не в браузерном хранилище, логах чатов или промптах. Полный сценарий и детали заголовков: [Аутентификация и доступ](https://docs.fastnear.com/ru/auth). ## Как вынимать чистую документацию в промпт @@ -137,3 +142,10 @@ curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" - Нужна глубина маршрутизации и компромиссы? [Как выбрать подходящую поверхность](https://docs.fastnear.com/ru/agents/choosing-surfaces) - Нужен режим работы с учётными данными и обращение с секретами? [Аутентификация для агентов](https://docs.fastnear.com/ru/agents/auth) - Нужны примеры сценариев? [Плейбуки для агентов](https://docs.fastnear.com/ru/agents/playbooks) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/agents/playbooks.md b/static/ru/agents/playbooks.md index fa1cd05..a6a1821 100644 --- a/static/ru/agents/playbooks.md +++ b/static/ru/agents/playbooks.md @@ -260,3 +260,10 @@ - используйте [Как выбрать подходящую поверхность](https://docs.fastnear.com/ru/agents/choosing-surfaces), чтобы выбрать первый API - используйте [Аутентификацию для агентов](https://docs.fastnear.com/ru/agents/auth), если блокер — работа с учётными данными - возвращайтесь к [Агентам на FastNear](https://docs.fastnear.com/ru/agents) за правилами рабочего цикла по умолчанию и формы ответа +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/agents/playbooks/index.md b/static/ru/agents/playbooks/index.md index fa1cd05..a6a1821 100644 --- a/static/ru/agents/playbooks/index.md +++ b/static/ru/agents/playbooks/index.md @@ -260,3 +260,10 @@ - используйте [Как выбрать подходящую поверхность](https://docs.fastnear.com/ru/agents/choosing-surfaces), чтобы выбрать первый API - используйте [Аутентификацию для агентов](https://docs.fastnear.com/ru/agents/auth), если блокер — работа с учётными данными - возвращайтесь к [Агентам на FastNear](https://docs.fastnear.com/ru/agents) за правилами рабочего цикла по умолчанию и формы ответа +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api.md b/static/ru/api.md index fb220d4..8d937ae 100644 --- a/static/ru/api.md +++ b/static/ru/api.md @@ -46,6 +46,10 @@ https://test.api.fastnear.com - [V1 поиск по публичному ключу](https://docs.fastnear.com/ru/api/v1/public-key) — когда нужно определить аккаунт по ключу. - [V1 топ держателей FT](https://docs.fastnear.com/ru/api/v1/ft-top) — для представлений распределения токенов. +## Нужен сценарий? + +Используйте [примеры FastNear API](https://docs.fastnear.com/ru/api/examples) для практических примеров: сводки по аккаунтам, определения аккаунта по ключу и перехода к узким представлениям активов. + ## Устранение неполадок ### Мне нужно только одно низкоуровневое значение из состояния цепочки @@ -59,3 +63,10 @@ https://test.api.fastnear.com ### Мне нужны транзакции, а не балансы Переходите в [Транзакции API](https://docs.fastnear.com/ru/tx), чтобы не перегружать поверхность представления аккаунта запросами по истории. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/examples.md b/static/ru/api/examples.md new file mode 100644 index 0000000..9d35825 --- /dev/null +++ b/static/ru/api/examples.md @@ -0,0 +1,205 @@ +**Источник:** [https://docs.fastnear.com/ru/api/examples](https://docs.fastnear.com/ru/api/examples) + +## Примеры + +Все shell-примеры ниже работают на публичных FastNear API-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### Свести один аккаунт за один вызов + +`/v1/account/{id}/full` — это агрегатор аккаунтов в FastNear API: один вызов собирает NEAR-состояние аккаунта, каждый FT-контракт, которого он касался, каждую NFT-коллекцию, которую он получил, и каждый валидаторский пул, в который делегировал. Если у вас уже есть `account_id`, это самый быстрый ответ на вопрос «что это за аккаунт?». + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + account_id, + near_balance_yocto: .state.balance, + ft_contracts: (.tokens | length), + nft_contracts: (.nfts | length), + staking_pool_contracts: (.pools | length) + }' +``` + +Для `root.near`: 150 FT-контрактов в списке, 102 NFT-коллекции, 2 валидаторских пула. Одни только счётчики контрактов говорят, что это оживлённый mainnet-аккаунт. Все примеры ниже погружаются в какую-то одну из этих поверхностей — начинайте отсюда, когда на руках только ID аккаунта. + +### Определить аккаунт по публичному ключу и сразу получить сводку + +Найдите, какому аккаунту принадлежит ключ, и прочитайте его активы за один следующий запрос. + +```bash +PUBLIC_KEY='ed25519:CCaThr3uokqnUs6Z5vVnaDcJdrfuTpYJHJWcAGubDjT' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +LOOKUP="$(curl -s "https://api.fastnear.com/v1/public_key/$(jq -rn --arg k "$PUBLIC_KEY" '$k | @uri')" \ + "${AUTH_HEADER[@]}")" + +echo "$LOOKUP" | jq '{matched: (.account_ids | length), account_ids}' + +ACCOUNT_ID="$(echo "$LOOKUP" | jq -r '.account_ids[0]')" + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq '{account_id, state, tokens: (.tokens|length), nfts: (.nfts|length), pools: (.pools|length)}' +``` + +Если `matched` больше 1, переключайтесь на [V1 Public Key Lookup All](https://docs.fastnear.com/ru/api/v1/public-key-all) и пройдитесь по каждому найденному аккаунту. + +### Сколько NEAR на этом аккаунте реально доступно к переводу? + +Состояние аккаунта NEAR делится на три ведра, которые UI кошельков обычно сливает в одно: `balance` — это свободная часть (не в стейкинге), `locked` — NEAR, привязанный к валидаторскому стейку или lockup-контракту, а `storage_bytes` подразумевает ещё отдельную долю, пришпиленную к trie по текущей ставке 10^19 yoctoNEAR за байт. Один pipeline над `/full` разводит их по полкам. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq ' + (.state.balance | tonumber) as $amount + | (.state.locked | tonumber) as $locked + | (.state.storage_bytes * 10000000000000000000) as $pinned + | 1e24 as $ynear + | { + account_id, + near: { + total_owned: (($amount + $locked) / $ynear), + unstaked: ($amount / $ynear), + stake_or_lockup: ($locked / $ynear), + pinned_to_storage: ($pinned / $ynear), + spendable: (($amount - $pinned) / $ynear) + } + }' +``` + +Для `root.near`: ~3914.67 NEAR всего, всё в свободной части, ~0.28677 NEAR закреплено за 28,677 байтами on-chain-состояния, ~3914.38 NEAR доступно к переводу. Новым аккаунтам это особенно заметно — свежесозданный именованный аккаунт ~182 байта «съедает» ~0.00182 NEAR под storage, и именно поэтому CLI-утилиты не дают отправить полный баланс. + +Наведите тот же pipeline на валидаторский пул вроде `astro-stakers.poolv1.near`, и пропорции перевернутся: ~730 тыс. свободных, ~27.68 млн в `locked`. Этот `locked` — собственный протокольный валидаторский стейк пула, а не средства делегатов (те учитываются внутри состояния контракта пула). Одно и то же поле означает разное на разных типах аккаунтов. + +jq считает в IEEE-754 double, поэтому NEAR-значения выше — только для отображения; для точной бухгалтерии сохраняйте сами yocto-строки. + +### Когда в этом аккаунте что-либо последний раз менялось? + +У каждой записи в массивах `tokens`, `nfts` и `pools` внутри `/full` есть собственное `last_update_block_height` — блок, в котором индексер последний раз видел изменение этой строки для этого аккаунта. Максимум по всем трём массивам даёт дешёвый сигнал «последняя активность» без похода в Transactions API. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq ' + [ + (.tokens // [])[].last_update_block_height, + (.nfts // [])[].last_update_block_height, + (.pools // [])[].last_update_block_height + ] as $heights + | ($heights | map(select(. != null))) as $tracked + | { + account_id, + total_entries: ($heights | length), + tracked_entries: ($tracked | length), + most_recent_block: ($tracked | max), + oldest_tracked_block: ($tracked | min) + }' +``` + +Для `root.near` это возвращает 254 записи по FT-, NFT- и pool-контрактам, 158 с отслеживаемым блоком и самый свежий блок `194301659`. Этого уже достаточно, чтобы понять, что кошелёк живой, не заходя в историю транзакций. + +Это правильный вопрос для «был ли этот кошелёк недавно активен?» или «двигалось ли что-то после блока X?» — дёшево, один запрос, без истории транзакций. Чтобы достать саму транзакцию, вызвавшую последнее изменение, расширяйте поверхность до [Transactions API](https://docs.fastnear.com/ru/tx). Записи с `last_update_block_height: null` относятся ко времени до per-row-отслеживания индексером (обычно старые airdrops) и здесь игнорируются, а не считаются свежими. + +### Показать NFT-коллекции этого кошелька от конкретного издателя + +Имена аккаунтов на NEAR кодируют иерархию: `mint.sharddog.near` — это подаккаунт `sharddog.near`, который, в свою очередь, — подаккаунт `near`. Издатели, выпускающие несколько NFT-коллекций, обычно разворачивают каждую как отдельный подаккаунт, поэтому один фильтр по суффиксу над NFT-списком аккаунта вытаскивает всё опубликованное под одним деревом — без внешнего реестра коллекций. + +```bash +ACCOUNT_ID=root.near +PUBLISHER=sharddog.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/nft" \ + "${AUTH_HEADER[@]}" \ + | jq --arg publisher "$PUBLISHER" ' + ("." + $publisher) as $suffix + | { + account_id: .account_id, + publisher: $publisher, + collections: [ + .tokens[] + | select(.contract_id | endswith($suffix)) + | { + contract_id, + last_update_block_height, + status: (if .last_update_block_height == null then "dormant" else "active" end) + } + ] | sort_by(.last_update_block_height // 0) + }' +``` + +Для `root.near` и `sharddog.near` это возвращает четыре контракта-подаккаунта: `ndcconstellationnft`, `mint`, `harvestmoon` и `claim`. Только у `claim` есть ненулевой `last_update_block_height` (`131402024`), так что именно этот контракт явно менял позицию кошелька. Остальные — спящие, что типично для одноразовых drop-контрактов, в которые аккаунт что-то получил и больше не возвращался. + +Поменяйте `PUBLISHER` на любой аккаунт, чтобы сфокусировать фильтр на другом дереве издателя. + +### Показывает ли кошелёк прямой стейкинг, liquid staking-токены или оба варианта? + +Прямые позиции в пулах лежат на `/staking`; liquid staking-токены (stNEAR, LiNEAR и т. п.) лежат на `/ft` как обычные FT. Прочитайте оба эндпоинта и классифицируйте кошелёк — `root.near` оказывается `mixed`. + +```bash +ACCOUNT_ID=root.near +LIQUID_PROVIDERS_JSON='["meta-pool.near","lst.rhealab.near","linear-protocol.near"]' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +STAKING="$(curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/staking" \ + "${AUTH_HEADER[@]}")" +FT="$(curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/ft" \ + "${AUTH_HEADER[@]}")" + +jq -n \ + --argjson staking "$STAKING" \ + --argjson ft "$FT" \ + --argjson providers "$LIQUID_PROVIDERS_JSON" ' + ($staking.pools // []) as $direct + | (($ft.tokens // []) | map(select(.contract_id as $id | $providers | index($id)))) as $liquid + | { + classification: ( + if ($direct|length)>0 and ($liquid|length)>0 then "mixed" + elif ($direct|length)>0 then "direct_only" + elif ($liquid|length)>0 then "liquid_only" + else "no_visible_staking_position" end + ), + direct_pools: ($direct | map(.pool_id)), + liquid_tokens: ($liquid | map({contract_id, balance})) + }' +``` + +Классификатор знает только то, чему вы его научили — расширяйте `LIQUID_PROVIDERS_JSON` по мере появления новых liquid staking-продуктов и рассматривайте результат как наблюдательный, а не исчерпывающий. + +## Частые ошибки + +- Сразу идти в широкий снимок аккаунта, когда пользователя интересует только одна категория активов. +- Использовать FastNear API, хотя пользователю нужны точные поля RPC или права доступа. +- Оставаться на страницах сводок по аккаунту, когда вопрос уже стал вопросом об истории транзакций. + +## Связанные страницы + +- [FastNear API](https://docs.fastnear.com/ru/api) +- [API Reference](https://docs.fastnear.com/ru/api/reference) +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [Transactions API](https://docs.fastnear.com/ru/tx) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/examples/index.md b/static/ru/api/examples/index.md new file mode 100644 index 0000000..9d35825 --- /dev/null +++ b/static/ru/api/examples/index.md @@ -0,0 +1,205 @@ +**Источник:** [https://docs.fastnear.com/ru/api/examples](https://docs.fastnear.com/ru/api/examples) + +## Примеры + +Все shell-примеры ниже работают на публичных FastNear API-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### Свести один аккаунт за один вызов + +`/v1/account/{id}/full` — это агрегатор аккаунтов в FastNear API: один вызов собирает NEAR-состояние аккаунта, каждый FT-контракт, которого он касался, каждую NFT-коллекцию, которую он получил, и каждый валидаторский пул, в который делегировал. Если у вас уже есть `account_id`, это самый быстрый ответ на вопрос «что это за аккаунт?». + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + account_id, + near_balance_yocto: .state.balance, + ft_contracts: (.tokens | length), + nft_contracts: (.nfts | length), + staking_pool_contracts: (.pools | length) + }' +``` + +Для `root.near`: 150 FT-контрактов в списке, 102 NFT-коллекции, 2 валидаторских пула. Одни только счётчики контрактов говорят, что это оживлённый mainnet-аккаунт. Все примеры ниже погружаются в какую-то одну из этих поверхностей — начинайте отсюда, когда на руках только ID аккаунта. + +### Определить аккаунт по публичному ключу и сразу получить сводку + +Найдите, какому аккаунту принадлежит ключ, и прочитайте его активы за один следующий запрос. + +```bash +PUBLIC_KEY='ed25519:CCaThr3uokqnUs6Z5vVnaDcJdrfuTpYJHJWcAGubDjT' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +LOOKUP="$(curl -s "https://api.fastnear.com/v1/public_key/$(jq -rn --arg k "$PUBLIC_KEY" '$k | @uri')" \ + "${AUTH_HEADER[@]}")" + +echo "$LOOKUP" | jq '{matched: (.account_ids | length), account_ids}' + +ACCOUNT_ID="$(echo "$LOOKUP" | jq -r '.account_ids[0]')" + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq '{account_id, state, tokens: (.tokens|length), nfts: (.nfts|length), pools: (.pools|length)}' +``` + +Если `matched` больше 1, переключайтесь на [V1 Public Key Lookup All](https://docs.fastnear.com/ru/api/v1/public-key-all) и пройдитесь по каждому найденному аккаунту. + +### Сколько NEAR на этом аккаунте реально доступно к переводу? + +Состояние аккаунта NEAR делится на три ведра, которые UI кошельков обычно сливает в одно: `balance` — это свободная часть (не в стейкинге), `locked` — NEAR, привязанный к валидаторскому стейку или lockup-контракту, а `storage_bytes` подразумевает ещё отдельную долю, пришпиленную к trie по текущей ставке 10^19 yoctoNEAR за байт. Один pipeline над `/full` разводит их по полкам. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq ' + (.state.balance | tonumber) as $amount + | (.state.locked | tonumber) as $locked + | (.state.storage_bytes * 10000000000000000000) as $pinned + | 1e24 as $ynear + | { + account_id, + near: { + total_owned: (($amount + $locked) / $ynear), + unstaked: ($amount / $ynear), + stake_or_lockup: ($locked / $ynear), + pinned_to_storage: ($pinned / $ynear), + spendable: (($amount - $pinned) / $ynear) + } + }' +``` + +Для `root.near`: ~3914.67 NEAR всего, всё в свободной части, ~0.28677 NEAR закреплено за 28,677 байтами on-chain-состояния, ~3914.38 NEAR доступно к переводу. Новым аккаунтам это особенно заметно — свежесозданный именованный аккаунт ~182 байта «съедает» ~0.00182 NEAR под storage, и именно поэтому CLI-утилиты не дают отправить полный баланс. + +Наведите тот же pipeline на валидаторский пул вроде `astro-stakers.poolv1.near`, и пропорции перевернутся: ~730 тыс. свободных, ~27.68 млн в `locked`. Этот `locked` — собственный протокольный валидаторский стейк пула, а не средства делегатов (те учитываются внутри состояния контракта пула). Одно и то же поле означает разное на разных типах аккаунтов. + +jq считает в IEEE-754 double, поэтому NEAR-значения выше — только для отображения; для точной бухгалтерии сохраняйте сами yocto-строки. + +### Когда в этом аккаунте что-либо последний раз менялось? + +У каждой записи в массивах `tokens`, `nfts` и `pools` внутри `/full` есть собственное `last_update_block_height` — блок, в котором индексер последний раз видел изменение этой строки для этого аккаунта. Максимум по всем трём массивам даёт дешёвый сигнал «последняя активность» без похода в Transactions API. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq ' + [ + (.tokens // [])[].last_update_block_height, + (.nfts // [])[].last_update_block_height, + (.pools // [])[].last_update_block_height + ] as $heights + | ($heights | map(select(. != null))) as $tracked + | { + account_id, + total_entries: ($heights | length), + tracked_entries: ($tracked | length), + most_recent_block: ($tracked | max), + oldest_tracked_block: ($tracked | min) + }' +``` + +Для `root.near` это возвращает 254 записи по FT-, NFT- и pool-контрактам, 158 с отслеживаемым блоком и самый свежий блок `194301659`. Этого уже достаточно, чтобы понять, что кошелёк живой, не заходя в историю транзакций. + +Это правильный вопрос для «был ли этот кошелёк недавно активен?» или «двигалось ли что-то после блока X?» — дёшево, один запрос, без истории транзакций. Чтобы достать саму транзакцию, вызвавшую последнее изменение, расширяйте поверхность до [Transactions API](https://docs.fastnear.com/ru/tx). Записи с `last_update_block_height: null` относятся ко времени до per-row-отслеживания индексером (обычно старые airdrops) и здесь игнорируются, а не считаются свежими. + +### Показать NFT-коллекции этого кошелька от конкретного издателя + +Имена аккаунтов на NEAR кодируют иерархию: `mint.sharddog.near` — это подаккаунт `sharddog.near`, который, в свою очередь, — подаккаунт `near`. Издатели, выпускающие несколько NFT-коллекций, обычно разворачивают каждую как отдельный подаккаунт, поэтому один фильтр по суффиксу над NFT-списком аккаунта вытаскивает всё опубликованное под одним деревом — без внешнего реестра коллекций. + +```bash +ACCOUNT_ID=root.near +PUBLISHER=sharddog.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/nft" \ + "${AUTH_HEADER[@]}" \ + | jq --arg publisher "$PUBLISHER" ' + ("." + $publisher) as $suffix + | { + account_id: .account_id, + publisher: $publisher, + collections: [ + .tokens[] + | select(.contract_id | endswith($suffix)) + | { + contract_id, + last_update_block_height, + status: (if .last_update_block_height == null then "dormant" else "active" end) + } + ] | sort_by(.last_update_block_height // 0) + }' +``` + +Для `root.near` и `sharddog.near` это возвращает четыре контракта-подаккаунта: `ndcconstellationnft`, `mint`, `harvestmoon` и `claim`. Только у `claim` есть ненулевой `last_update_block_height` (`131402024`), так что именно этот контракт явно менял позицию кошелька. Остальные — спящие, что типично для одноразовых drop-контрактов, в которые аккаунт что-то получил и больше не возвращался. + +Поменяйте `PUBLISHER` на любой аккаунт, чтобы сфокусировать фильтр на другом дереве издателя. + +### Показывает ли кошелёк прямой стейкинг, liquid staking-токены или оба варианта? + +Прямые позиции в пулах лежат на `/staking`; liquid staking-токены (stNEAR, LiNEAR и т. п.) лежат на `/ft` как обычные FT. Прочитайте оба эндпоинта и классифицируйте кошелёк — `root.near` оказывается `mixed`. + +```bash +ACCOUNT_ID=root.near +LIQUID_PROVIDERS_JSON='["meta-pool.near","lst.rhealab.near","linear-protocol.near"]' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +STAKING="$(curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/staking" \ + "${AUTH_HEADER[@]}")" +FT="$(curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/ft" \ + "${AUTH_HEADER[@]}")" + +jq -n \ + --argjson staking "$STAKING" \ + --argjson ft "$FT" \ + --argjson providers "$LIQUID_PROVIDERS_JSON" ' + ($staking.pools // []) as $direct + | (($ft.tokens // []) | map(select(.contract_id as $id | $providers | index($id)))) as $liquid + | { + classification: ( + if ($direct|length)>0 and ($liquid|length)>0 then "mixed" + elif ($direct|length)>0 then "direct_only" + elif ($liquid|length)>0 then "liquid_only" + else "no_visible_staking_position" end + ), + direct_pools: ($direct | map(.pool_id)), + liquid_tokens: ($liquid | map({contract_id, balance})) + }' +``` + +Классификатор знает только то, чему вы его научили — расширяйте `LIQUID_PROVIDERS_JSON` по мере появления новых liquid staking-продуктов и рассматривайте результат как наблюдательный, а не исчерпывающий. + +## Частые ошибки + +- Сразу идти в широкий снимок аккаунта, когда пользователя интересует только одна категория активов. +- Использовать FastNear API, хотя пользователю нужны точные поля RPC или права доступа. +- Оставаться на страницах сводок по аккаунту, когда вопрос уже стал вопросом об истории транзакций. + +## Связанные страницы + +- [FastNear API](https://docs.fastnear.com/ru/api) +- [API Reference](https://docs.fastnear.com/ru/api/reference) +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [Transactions API](https://docs.fastnear.com/ru/tx) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/index.md b/static/ru/api/index.md index fb220d4..8d937ae 100644 --- a/static/ru/api/index.md +++ b/static/ru/api/index.md @@ -46,6 +46,10 @@ https://test.api.fastnear.com - [V1 поиск по публичному ключу](https://docs.fastnear.com/ru/api/v1/public-key) — когда нужно определить аккаунт по ключу. - [V1 топ держателей FT](https://docs.fastnear.com/ru/api/v1/ft-top) — для представлений распределения токенов. +## Нужен сценарий? + +Используйте [примеры FastNear API](https://docs.fastnear.com/ru/api/examples) для практических примеров: сводки по аккаунтам, определения аккаунта по ключу и перехода к узким представлениям активов. + ## Устранение неполадок ### Мне нужно только одно низкоуровневое значение из состояния цепочки @@ -59,3 +63,10 @@ https://test.api.fastnear.com ### Мне нужны транзакции, а не балансы Переходите в [Транзакции API](https://docs.fastnear.com/ru/tx), чтобы не перегружать поверхность представления аккаунта запросами по истории. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/reference.md b/static/ru/api/reference.md index 236514f..c2b2441 100644 --- a/static/ru/api/reference.md +++ b/static/ru/api/reference.md @@ -48,3 +48,10 @@ - [Агенты на FastNear](https://docs.fastnear.com/ru/agents) - [Как выбрать подходящую поверхность](https://docs.fastnear.com/ru/agents/choosing-surfaces) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/reference/index.md b/static/ru/api/reference/index.md index 236514f..c2b2441 100644 --- a/static/ru/api/reference/index.md +++ b/static/ru/api/reference/index.md @@ -48,3 +48,10 @@ - [Агенты на FastNear](https://docs.fastnear.com/ru/agents) - [Как выбрать подходящую поверхность](https://docs.fastnear.com/ru/agents/choosing-surfaces) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/system/health.md b/static/ru/api/system/health.md index c52c3c5..8a56f42 100644 --- a/static/ru/api/system/health.md +++ b/static/ru/api/system/health.md @@ -59,3 +59,10 @@ "refName": "HealthResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/system/health/index.md b/static/ru/api/system/health/index.md index c52c3c5..8a56f42 100644 --- a/static/ru/api/system/health/index.md +++ b/static/ru/api/system/health/index.md @@ -59,3 +59,10 @@ "refName": "HealthResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/system/status.md b/static/ru/api/system/status.md index 3d3b230..dfc602d 100644 --- a/static/ru/api/system/status.md +++ b/static/ru/api/system/status.md @@ -94,3 +94,10 @@ "refName": "StatusResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/system/status/index.md b/static/ru/api/system/status/index.md index 3d3b230..dfc602d 100644 --- a/static/ru/api/system/status/index.md +++ b/static/ru/api/system/status/index.md @@ -94,3 +94,10 @@ "refName": "StatusResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v0/account-ft.md b/static/ru/api/v0/account-ft.md index 4e003b6..898302f 100644 --- a/static/ru/api/v0/account-ft.md +++ b/static/ru/api/v0/account-ft.md @@ -78,3 +78,10 @@ "refName": "V0ContractsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v0/account-ft/index.md b/static/ru/api/v0/account-ft/index.md index 4e003b6..898302f 100644 --- a/static/ru/api/v0/account-ft/index.md +++ b/static/ru/api/v0/account-ft/index.md @@ -78,3 +78,10 @@ "refName": "V0ContractsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v0/account-nft.md b/static/ru/api/v0/account-nft.md index 1e25eec..e991c28 100644 --- a/static/ru/api/v0/account-nft.md +++ b/static/ru/api/v0/account-nft.md @@ -78,3 +78,10 @@ "refName": "V0ContractsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v0/account-nft/index.md b/static/ru/api/v0/account-nft/index.md index 1e25eec..e991c28 100644 --- a/static/ru/api/v0/account-nft/index.md +++ b/static/ru/api/v0/account-nft/index.md @@ -78,3 +78,10 @@ "refName": "V0ContractsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v0/account-staking.md b/static/ru/api/v0/account-staking.md index ea5a4ce..7583a06 100644 --- a/static/ru/api/v0/account-staking.md +++ b/static/ru/api/v0/account-staking.md @@ -78,3 +78,10 @@ "refName": "V0StakingResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v0/account-staking/index.md b/static/ru/api/v0/account-staking/index.md index ea5a4ce..7583a06 100644 --- a/static/ru/api/v0/account-staking/index.md +++ b/static/ru/api/v0/account-staking/index.md @@ -78,3 +78,10 @@ "refName": "V0StakingResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v0/public-key-all.md b/static/ru/api/v0/public-key-all.md index be03dd0..deb2ada 100644 --- a/static/ru/api/v0/public-key-all.md +++ b/static/ru/api/v0/public-key-all.md @@ -78,3 +78,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v0/public-key-all/index.md b/static/ru/api/v0/public-key-all/index.md index be03dd0..deb2ada 100644 --- a/static/ru/api/v0/public-key-all/index.md +++ b/static/ru/api/v0/public-key-all/index.md @@ -78,3 +78,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v0/public-key.md b/static/ru/api/v0/public-key.md index 7e23c9c..8c786d4 100644 --- a/static/ru/api/v0/public-key.md +++ b/static/ru/api/v0/public-key.md @@ -78,3 +78,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v0/public-key/index.md b/static/ru/api/v0/public-key/index.md index 7e23c9c..8c786d4 100644 --- a/static/ru/api/v0/public-key/index.md +++ b/static/ru/api/v0/public-key/index.md @@ -78,3 +78,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/account-ft.md b/static/ru/api/v1/account-ft.md index 04cd04a..25c9502 100644 --- a/static/ru/api/v1/account-ft.md +++ b/static/ru/api/v1/account-ft.md @@ -109,3 +109,10 @@ "refName": "V1FtResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/account-ft/index.md b/static/ru/api/v1/account-ft/index.md index 04cd04a..25c9502 100644 --- a/static/ru/api/v1/account-ft/index.md +++ b/static/ru/api/v1/account-ft/index.md @@ -109,3 +109,10 @@ "refName": "V1FtResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/account-full.md b/static/ru/api/v1/account-full.md index 7fba3f7..afb7698 100644 --- a/static/ru/api/v1/account-full.md +++ b/static/ru/api/v1/account-full.md @@ -185,3 +185,10 @@ "refName": "AccountFullResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/account-full/index.md b/static/ru/api/v1/account-full/index.md index 7fba3f7..afb7698 100644 --- a/static/ru/api/v1/account-full/index.md +++ b/static/ru/api/v1/account-full/index.md @@ -185,3 +185,10 @@ "refName": "AccountFullResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/account-nft.md b/static/ru/api/v1/account-nft.md index 33ca813..755cc70 100644 --- a/static/ru/api/v1/account-nft.md +++ b/static/ru/api/v1/account-nft.md @@ -101,3 +101,10 @@ "refName": "V1NftResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/account-nft/index.md b/static/ru/api/v1/account-nft/index.md index 33ca813..755cc70 100644 --- a/static/ru/api/v1/account-nft/index.md +++ b/static/ru/api/v1/account-nft/index.md @@ -101,3 +101,10 @@ "refName": "V1NftResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/account-staking.md b/static/ru/api/v1/account-staking.md index 586bd82..ce9eeec 100644 --- a/static/ru/api/v1/account-staking.md +++ b/static/ru/api/v1/account-staking.md @@ -101,3 +101,10 @@ "refName": "V1StakingResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/account-staking/index.md b/static/ru/api/v1/account-staking/index.md index 586bd82..ce9eeec 100644 --- a/static/ru/api/v1/account-staking/index.md +++ b/static/ru/api/v1/account-staking/index.md @@ -101,3 +101,10 @@ "refName": "V1StakingResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/ft-top.md b/static/ru/api/v1/ft-top.md index ce74821..fdfa343 100644 --- a/static/ru/api/v1/ft-top.md +++ b/static/ru/api/v1/ft-top.md @@ -100,3 +100,10 @@ "refName": "TokenAccountsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/ft-top/index.md b/static/ru/api/v1/ft-top/index.md index ce74821..fdfa343 100644 --- a/static/ru/api/v1/ft-top/index.md +++ b/static/ru/api/v1/ft-top/index.md @@ -100,3 +100,10 @@ "refName": "TokenAccountsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/public-key-all.md b/static/ru/api/v1/public-key-all.md index 8a1d15f..fd250d7 100644 --- a/static/ru/api/v1/public-key-all.md +++ b/static/ru/api/v1/public-key-all.md @@ -78,3 +78,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/public-key-all/index.md b/static/ru/api/v1/public-key-all/index.md index 8a1d15f..fd250d7 100644 --- a/static/ru/api/v1/public-key-all/index.md +++ b/static/ru/api/v1/public-key-all/index.md @@ -78,3 +78,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/public-key.md b/static/ru/api/v1/public-key.md index 418eb5a..6d42929 100644 --- a/static/ru/api/v1/public-key.md +++ b/static/ru/api/v1/public-key.md @@ -78,3 +78,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/api/v1/public-key/index.md b/static/ru/api/v1/public-key/index.md index 418eb5a..6d42929 100644 --- a/static/ru/api/v1/public-key/index.md +++ b/static/ru/api/v1/public-key/index.md @@ -78,3 +78,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/system/health.md b/static/ru/apis/fastnear/system/health.md index 1cff258..bb40ff6 100644 --- a/static/ru/apis/fastnear/system/health.md +++ b/static/ru/apis/fastnear/system/health.md @@ -58,3 +58,10 @@ "refName": "HealthResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/system/health/index.md b/static/ru/apis/fastnear/system/health/index.md index 1cff258..bb40ff6 100644 --- a/static/ru/apis/fastnear/system/health/index.md +++ b/static/ru/apis/fastnear/system/health/index.md @@ -58,3 +58,10 @@ "refName": "HealthResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/system/status.md b/static/ru/apis/fastnear/system/status.md index 8726dd0..5eed230 100644 --- a/static/ru/apis/fastnear/system/status.md +++ b/static/ru/apis/fastnear/system/status.md @@ -93,3 +93,10 @@ "refName": "StatusResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/system/status/index.md b/static/ru/apis/fastnear/system/status/index.md index 8726dd0..5eed230 100644 --- a/static/ru/apis/fastnear/system/status/index.md +++ b/static/ru/apis/fastnear/system/status/index.md @@ -93,3 +93,10 @@ "refName": "StatusResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v0/account_ft.md b/static/ru/apis/fastnear/v0/account_ft.md index 84991c5..0f1ae96 100644 --- a/static/ru/apis/fastnear/v0/account_ft.md +++ b/static/ru/apis/fastnear/v0/account_ft.md @@ -77,3 +77,10 @@ "refName": "V0ContractsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v0/account_ft/index.md b/static/ru/apis/fastnear/v0/account_ft/index.md index 84991c5..0f1ae96 100644 --- a/static/ru/apis/fastnear/v0/account_ft/index.md +++ b/static/ru/apis/fastnear/v0/account_ft/index.md @@ -77,3 +77,10 @@ "refName": "V0ContractsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v0/account_nft.md b/static/ru/apis/fastnear/v0/account_nft.md index 1e35646..a90eb82 100644 --- a/static/ru/apis/fastnear/v0/account_nft.md +++ b/static/ru/apis/fastnear/v0/account_nft.md @@ -77,3 +77,10 @@ "refName": "V0ContractsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v0/account_nft/index.md b/static/ru/apis/fastnear/v0/account_nft/index.md index 1e35646..a90eb82 100644 --- a/static/ru/apis/fastnear/v0/account_nft/index.md +++ b/static/ru/apis/fastnear/v0/account_nft/index.md @@ -77,3 +77,10 @@ "refName": "V0ContractsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v0/account_staking.md b/static/ru/apis/fastnear/v0/account_staking.md index 5d43ba0..103f697 100644 --- a/static/ru/apis/fastnear/v0/account_staking.md +++ b/static/ru/apis/fastnear/v0/account_staking.md @@ -77,3 +77,10 @@ "refName": "V0StakingResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v0/account_staking/index.md b/static/ru/apis/fastnear/v0/account_staking/index.md index 5d43ba0..103f697 100644 --- a/static/ru/apis/fastnear/v0/account_staking/index.md +++ b/static/ru/apis/fastnear/v0/account_staking/index.md @@ -77,3 +77,10 @@ "refName": "V0StakingResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v0/public_key_lookup.md b/static/ru/apis/fastnear/v0/public_key_lookup.md index 5dd30be..c5a904f 100644 --- a/static/ru/apis/fastnear/v0/public_key_lookup.md +++ b/static/ru/apis/fastnear/v0/public_key_lookup.md @@ -77,3 +77,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v0/public_key_lookup/index.md b/static/ru/apis/fastnear/v0/public_key_lookup/index.md index 5dd30be..c5a904f 100644 --- a/static/ru/apis/fastnear/v0/public_key_lookup/index.md +++ b/static/ru/apis/fastnear/v0/public_key_lookup/index.md @@ -77,3 +77,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v0/public_key_lookup_all.md b/static/ru/apis/fastnear/v0/public_key_lookup_all.md index 7a1470a..8d33394 100644 --- a/static/ru/apis/fastnear/v0/public_key_lookup_all.md +++ b/static/ru/apis/fastnear/v0/public_key_lookup_all.md @@ -77,3 +77,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v0/public_key_lookup_all/index.md b/static/ru/apis/fastnear/v0/public_key_lookup_all/index.md index 7a1470a..8d33394 100644 --- a/static/ru/apis/fastnear/v0/public_key_lookup_all/index.md +++ b/static/ru/apis/fastnear/v0/public_key_lookup_all/index.md @@ -77,3 +77,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/account_ft.md b/static/ru/apis/fastnear/v1/account_ft.md index cc3f74e..e04e673 100644 --- a/static/ru/apis/fastnear/v1/account_ft.md +++ b/static/ru/apis/fastnear/v1/account_ft.md @@ -108,3 +108,10 @@ "refName": "V1FtResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/account_ft/index.md b/static/ru/apis/fastnear/v1/account_ft/index.md index cc3f74e..e04e673 100644 --- a/static/ru/apis/fastnear/v1/account_ft/index.md +++ b/static/ru/apis/fastnear/v1/account_ft/index.md @@ -108,3 +108,10 @@ "refName": "V1FtResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/account_full.md b/static/ru/apis/fastnear/v1/account_full.md index e011b9d..d2b1b2b 100644 --- a/static/ru/apis/fastnear/v1/account_full.md +++ b/static/ru/apis/fastnear/v1/account_full.md @@ -184,3 +184,10 @@ "refName": "AccountFullResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/account_full/index.md b/static/ru/apis/fastnear/v1/account_full/index.md index e011b9d..d2b1b2b 100644 --- a/static/ru/apis/fastnear/v1/account_full/index.md +++ b/static/ru/apis/fastnear/v1/account_full/index.md @@ -184,3 +184,10 @@ "refName": "AccountFullResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/account_nft.md b/static/ru/apis/fastnear/v1/account_nft.md index 4d3db21..427b7d4 100644 --- a/static/ru/apis/fastnear/v1/account_nft.md +++ b/static/ru/apis/fastnear/v1/account_nft.md @@ -100,3 +100,10 @@ "refName": "V1NftResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/account_nft/index.md b/static/ru/apis/fastnear/v1/account_nft/index.md index 4d3db21..427b7d4 100644 --- a/static/ru/apis/fastnear/v1/account_nft/index.md +++ b/static/ru/apis/fastnear/v1/account_nft/index.md @@ -100,3 +100,10 @@ "refName": "V1NftResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/account_staking.md b/static/ru/apis/fastnear/v1/account_staking.md index 79c2c29..ccb8052 100644 --- a/static/ru/apis/fastnear/v1/account_staking.md +++ b/static/ru/apis/fastnear/v1/account_staking.md @@ -100,3 +100,10 @@ "refName": "V1StakingResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/account_staking/index.md b/static/ru/apis/fastnear/v1/account_staking/index.md index 79c2c29..ccb8052 100644 --- a/static/ru/apis/fastnear/v1/account_staking/index.md +++ b/static/ru/apis/fastnear/v1/account_staking/index.md @@ -100,3 +100,10 @@ "refName": "V1StakingResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/ft_top.md b/static/ru/apis/fastnear/v1/ft_top.md index 26efa18..ee2fd86 100644 --- a/static/ru/apis/fastnear/v1/ft_top.md +++ b/static/ru/apis/fastnear/v1/ft_top.md @@ -99,3 +99,10 @@ "refName": "TokenAccountsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/ft_top/index.md b/static/ru/apis/fastnear/v1/ft_top/index.md index 26efa18..ee2fd86 100644 --- a/static/ru/apis/fastnear/v1/ft_top/index.md +++ b/static/ru/apis/fastnear/v1/ft_top/index.md @@ -99,3 +99,10 @@ "refName": "TokenAccountsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/public_key_lookup.md b/static/ru/apis/fastnear/v1/public_key_lookup.md index 162e5ea..566816c 100644 --- a/static/ru/apis/fastnear/v1/public_key_lookup.md +++ b/static/ru/apis/fastnear/v1/public_key_lookup.md @@ -77,3 +77,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/public_key_lookup/index.md b/static/ru/apis/fastnear/v1/public_key_lookup/index.md index 162e5ea..566816c 100644 --- a/static/ru/apis/fastnear/v1/public_key_lookup/index.md +++ b/static/ru/apis/fastnear/v1/public_key_lookup/index.md @@ -77,3 +77,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/public_key_lookup_all.md b/static/ru/apis/fastnear/v1/public_key_lookup_all.md index dbbb336..16f53e0 100644 --- a/static/ru/apis/fastnear/v1/public_key_lookup_all.md +++ b/static/ru/apis/fastnear/v1/public_key_lookup_all.md @@ -77,3 +77,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/fastnear/v1/public_key_lookup_all/index.md b/static/ru/apis/fastnear/v1/public_key_lookup_all/index.md index dbbb336..16f53e0 100644 --- a/static/ru/apis/fastnear/v1/public_key_lookup_all/index.md +++ b/static/ru/apis/fastnear/v1/public_key_lookup_all/index.md @@ -77,3 +77,10 @@ "refName": "PublicKeyLookupResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/all_by_predecessor.md b/static/ru/apis/kv-fastdata/v0/all_by_predecessor.md index 44226ab..c329791 100644 --- a/static/ru/apis/kv-fastdata/v0/all_by_predecessor.md +++ b/static/ru/apis/kv-fastdata/v0/all_by_predecessor.md @@ -206,3 +206,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/all_by_predecessor/index.md b/static/ru/apis/kv-fastdata/v0/all_by_predecessor/index.md index 44226ab..c329791 100644 --- a/static/ru/apis/kv-fastdata/v0/all_by_predecessor/index.md +++ b/static/ru/apis/kv-fastdata/v0/all_by_predecessor/index.md @@ -206,3 +206,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/get_history_key.md b/static/ru/apis/kv-fastdata/v0/get_history_key.md index 08b3d24..6938ec0 100644 --- a/static/ru/apis/kv-fastdata/v0/get_history_key.md +++ b/static/ru/apis/kv-fastdata/v0/get_history_key.md @@ -163,3 +163,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/get_history_key/index.md b/static/ru/apis/kv-fastdata/v0/get_history_key/index.md index 08b3d24..6938ec0 100644 --- a/static/ru/apis/kv-fastdata/v0/get_history_key/index.md +++ b/static/ru/apis/kv-fastdata/v0/get_history_key/index.md @@ -163,3 +163,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/get_latest_key.md b/static/ru/apis/kv-fastdata/v0/get_latest_key.md index 0aef926..5e19d0d 100644 --- a/static/ru/apis/kv-fastdata/v0/get_latest_key.md +++ b/static/ru/apis/kv-fastdata/v0/get_latest_key.md @@ -163,3 +163,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/get_latest_key/index.md b/static/ru/apis/kv-fastdata/v0/get_latest_key/index.md index 0aef926..5e19d0d 100644 --- a/static/ru/apis/kv-fastdata/v0/get_latest_key/index.md +++ b/static/ru/apis/kv-fastdata/v0/get_latest_key/index.md @@ -163,3 +163,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/history_by_account.md b/static/ru/apis/kv-fastdata/v0/history_by_account.md index 761dc86..df0c9f7 100644 --- a/static/ru/apis/kv-fastdata/v0/history_by_account.md +++ b/static/ru/apis/kv-fastdata/v0/history_by_account.md @@ -238,3 +238,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/history_by_account/index.md b/static/ru/apis/kv-fastdata/v0/history_by_account/index.md index 761dc86..df0c9f7 100644 --- a/static/ru/apis/kv-fastdata/v0/history_by_account/index.md +++ b/static/ru/apis/kv-fastdata/v0/history_by_account/index.md @@ -238,3 +238,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/history_by_key.md b/static/ru/apis/kv-fastdata/v0/history_by_key.md index 830b479..082cd03 100644 --- a/static/ru/apis/kv-fastdata/v0/history_by_key.md +++ b/static/ru/apis/kv-fastdata/v0/history_by_key.md @@ -224,3 +224,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/history_by_key/index.md b/static/ru/apis/kv-fastdata/v0/history_by_key/index.md index 830b479..082cd03 100644 --- a/static/ru/apis/kv-fastdata/v0/history_by_key/index.md +++ b/static/ru/apis/kv-fastdata/v0/history_by_key/index.md @@ -224,3 +224,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/history_by_predecessor.md b/static/ru/apis/kv-fastdata/v0/history_by_predecessor.md index bf60890..1c467c2 100644 --- a/static/ru/apis/kv-fastdata/v0/history_by_predecessor.md +++ b/static/ru/apis/kv-fastdata/v0/history_by_predecessor.md @@ -241,3 +241,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/history_by_predecessor/index.md b/static/ru/apis/kv-fastdata/v0/history_by_predecessor/index.md index bf60890..1c467c2 100644 --- a/static/ru/apis/kv-fastdata/v0/history_by_predecessor/index.md +++ b/static/ru/apis/kv-fastdata/v0/history_by_predecessor/index.md @@ -241,3 +241,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/latest_by_account.md b/static/ru/apis/kv-fastdata/v0/latest_by_account.md index a9b46ec..cbf86ce 100644 --- a/static/ru/apis/kv-fastdata/v0/latest_by_account.md +++ b/static/ru/apis/kv-fastdata/v0/latest_by_account.md @@ -226,3 +226,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/latest_by_account/index.md b/static/ru/apis/kv-fastdata/v0/latest_by_account/index.md index a9b46ec..cbf86ce 100644 --- a/static/ru/apis/kv-fastdata/v0/latest_by_account/index.md +++ b/static/ru/apis/kv-fastdata/v0/latest_by_account/index.md @@ -226,3 +226,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/latest_by_predecessor.md b/static/ru/apis/kv-fastdata/v0/latest_by_predecessor.md index bcb4d1d..0034078 100644 --- a/static/ru/apis/kv-fastdata/v0/latest_by_predecessor.md +++ b/static/ru/apis/kv-fastdata/v0/latest_by_predecessor.md @@ -229,3 +229,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/latest_by_predecessor/index.md b/static/ru/apis/kv-fastdata/v0/latest_by_predecessor/index.md index bcb4d1d..0034078 100644 --- a/static/ru/apis/kv-fastdata/v0/latest_by_predecessor/index.md +++ b/static/ru/apis/kv-fastdata/v0/latest_by_predecessor/index.md @@ -229,3 +229,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/multi.md b/static/ru/apis/kv-fastdata/v0/multi.md index b6deeb2..3507608 100644 --- a/static/ru/apis/kv-fastdata/v0/multi.md +++ b/static/ru/apis/kv-fastdata/v0/multi.md @@ -197,3 +197,10 @@ "refName": "MultiResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/kv-fastdata/v0/multi/index.md b/static/ru/apis/kv-fastdata/v0/multi/index.md index b6deeb2..3507608 100644 --- a/static/ru/apis/kv-fastdata/v0/multi/index.md +++ b/static/ru/apis/kv-fastdata/v0/multi/index.md @@ -197,3 +197,10 @@ "refName": "MultiResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/system/health.md b/static/ru/apis/neardata/system/health.md index 4a987c3..06d5e15 100644 --- a/static/ru/apis/neardata/system/health.md +++ b/static/ru/apis/neardata/system/health.md @@ -58,3 +58,10 @@ "refName": "HealthResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/system/health/index.md b/static/ru/apis/neardata/system/health/index.md index 4a987c3..06d5e15 100644 --- a/static/ru/apis/neardata/system/health/index.md +++ b/static/ru/apis/neardata/system/health/index.md @@ -58,3 +58,10 @@ "refName": "HealthResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/block.md b/static/ru/apis/neardata/v0/block.md index 15c9ddc..5c9569d 100644 --- a/static/ru/apis/neardata/v0/block.md +++ b/static/ru/apis/neardata/v0/block.md @@ -1850,3 +1850,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/block/index.md b/static/ru/apis/neardata/v0/block/index.md index 15c9ddc..5c9569d 100644 --- a/static/ru/apis/neardata/v0/block/index.md +++ b/static/ru/apis/neardata/v0/block/index.md @@ -1850,3 +1850,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/block_chunk.md b/static/ru/apis/neardata/v0/block_chunk.md index 5e588db..761be1f 100644 --- a/static/ru/apis/neardata/v0/block_chunk.md +++ b/static/ru/apis/neardata/v0/block_chunk.md @@ -905,3 +905,10 @@ "refName": "ChunkDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/block_chunk/index.md b/static/ru/apis/neardata/v0/block_chunk/index.md index 5e588db..761be1f 100644 --- a/static/ru/apis/neardata/v0/block_chunk/index.md +++ b/static/ru/apis/neardata/v0/block_chunk/index.md @@ -905,3 +905,10 @@ "refName": "ChunkDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/block_headers.md b/static/ru/apis/neardata/v0/block_headers.md index a87ac1e..0c4e456 100644 --- a/static/ru/apis/neardata/v0/block_headers.md +++ b/static/ru/apis/neardata/v0/block_headers.md @@ -250,3 +250,10 @@ "refName": "BlockEnvelope" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/block_headers/index.md b/static/ru/apis/neardata/v0/block_headers/index.md index a87ac1e..0c4e456 100644 --- a/static/ru/apis/neardata/v0/block_headers/index.md +++ b/static/ru/apis/neardata/v0/block_headers/index.md @@ -250,3 +250,10 @@ "refName": "BlockEnvelope" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/block_optimistic.md b/static/ru/apis/neardata/v0/block_optimistic.md index f800964..907aed8 100644 --- a/static/ru/apis/neardata/v0/block_optimistic.md +++ b/static/ru/apis/neardata/v0/block_optimistic.md @@ -1850,3 +1850,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/block_optimistic/index.md b/static/ru/apis/neardata/v0/block_optimistic/index.md index f800964..907aed8 100644 --- a/static/ru/apis/neardata/v0/block_optimistic/index.md +++ b/static/ru/apis/neardata/v0/block_optimistic/index.md @@ -1850,3 +1850,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/block_shard.md b/static/ru/apis/neardata/v0/block_shard.md index 469f464..09c2a1a 100644 --- a/static/ru/apis/neardata/v0/block_shard.md +++ b/static/ru/apis/neardata/v0/block_shard.md @@ -1629,3 +1629,10 @@ "refName": "ShardDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/block_shard/index.md b/static/ru/apis/neardata/v0/block_shard/index.md index 469f464..09c2a1a 100644 --- a/static/ru/apis/neardata/v0/block_shard/index.md +++ b/static/ru/apis/neardata/v0/block_shard/index.md @@ -1629,3 +1629,10 @@ "refName": "ShardDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/first_block.md b/static/ru/apis/neardata/v0/first_block.md index d768d13..e7e13b8 100644 --- a/static/ru/apis/neardata/v0/first_block.md +++ b/static/ru/apis/neardata/v0/first_block.md @@ -1842,3 +1842,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/first_block/index.md b/static/ru/apis/neardata/v0/first_block/index.md index d768d13..e7e13b8 100644 --- a/static/ru/apis/neardata/v0/first_block/index.md +++ b/static/ru/apis/neardata/v0/first_block/index.md @@ -1842,3 +1842,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/last_block_final.md b/static/ru/apis/neardata/v0/last_block_final.md index e0acdf6..10648e0 100644 --- a/static/ru/apis/neardata/v0/last_block_final.md +++ b/static/ru/apis/neardata/v0/last_block_final.md @@ -1842,3 +1842,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/last_block_final/index.md b/static/ru/apis/neardata/v0/last_block_final/index.md index e0acdf6..10648e0 100644 --- a/static/ru/apis/neardata/v0/last_block_final/index.md +++ b/static/ru/apis/neardata/v0/last_block_final/index.md @@ -1842,3 +1842,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/last_block_optimistic.md b/static/ru/apis/neardata/v0/last_block_optimistic.md index 8652ea8..83de3d2 100644 --- a/static/ru/apis/neardata/v0/last_block_optimistic.md +++ b/static/ru/apis/neardata/v0/last_block_optimistic.md @@ -1842,3 +1842,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/neardata/v0/last_block_optimistic/index.md b/static/ru/apis/neardata/v0/last_block_optimistic/index.md index 8652ea8..83de3d2 100644 --- a/static/ru/apis/neardata/v0/last_block_optimistic/index.md +++ b/static/ru/apis/neardata/v0/last_block_optimistic/index.md @@ -1842,3 +1842,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/transactions/v0/account.md b/static/ru/apis/transactions/v0/account.md index f4ac645..700d1db 100644 --- a/static/ru/apis/transactions/v0/account.md +++ b/static/ru/apis/transactions/v0/account.md @@ -413,3 +413,10 @@ "refName": "AccountResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/transactions/v0/account/index.md b/static/ru/apis/transactions/v0/account/index.md index f4ac645..700d1db 100644 --- a/static/ru/apis/transactions/v0/account/index.md +++ b/static/ru/apis/transactions/v0/account/index.md @@ -413,3 +413,10 @@ "refName": "AccountResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/transactions/v0/block.md b/static/ru/apis/transactions/v0/block.md index 7c808a1..b10cc99 100644 --- a/static/ru/apis/transactions/v0/block.md +++ b/static/ru/apis/transactions/v0/block.md @@ -588,3 +588,10 @@ "refName": "BlockResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/transactions/v0/block/index.md b/static/ru/apis/transactions/v0/block/index.md index 7c808a1..b10cc99 100644 --- a/static/ru/apis/transactions/v0/block/index.md +++ b/static/ru/apis/transactions/v0/block/index.md @@ -588,3 +588,10 @@ "refName": "BlockResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/transactions/v0/blocks.md b/static/ru/apis/transactions/v0/blocks.md index 70d322a..e3f061a 100644 --- a/static/ru/apis/transactions/v0/blocks.md +++ b/static/ru/apis/transactions/v0/blocks.md @@ -267,3 +267,10 @@ "refName": "BlocksResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/transactions/v0/blocks/index.md b/static/ru/apis/transactions/v0/blocks/index.md index 70d322a..e3f061a 100644 --- a/static/ru/apis/transactions/v0/blocks/index.md +++ b/static/ru/apis/transactions/v0/blocks/index.md @@ -267,3 +267,10 @@ "refName": "BlocksResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/transactions/v0/receipt.md b/static/ru/apis/transactions/v0/receipt.md index 845e4e4..cd5eee3 100644 --- a/static/ru/apis/transactions/v0/receipt.md +++ b/static/ru/apis/transactions/v0/receipt.md @@ -234,3 +234,10 @@ "refName": "ReceiptResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/transactions/v0/receipt/index.md b/static/ru/apis/transactions/v0/receipt/index.md index 845e4e4..cd5eee3 100644 --- a/static/ru/apis/transactions/v0/receipt/index.md +++ b/static/ru/apis/transactions/v0/receipt/index.md @@ -234,3 +234,10 @@ "refName": "ReceiptResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/transactions/v0/transactions.md b/static/ru/apis/transactions/v0/transactions.md index 4e409de..f685902 100644 --- a/static/ru/apis/transactions/v0/transactions.md +++ b/static/ru/apis/transactions/v0/transactions.md @@ -97,3 +97,10 @@ "refName": "TransactionsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/transactions/v0/transactions/index.md b/static/ru/apis/transactions/v0/transactions/index.md index 4e409de..f685902 100644 --- a/static/ru/apis/transactions/v0/transactions/index.md +++ b/static/ru/apis/transactions/v0/transactions/index.md @@ -97,3 +97,10 @@ "refName": "TransactionsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/transfers/v0/transfers.md b/static/ru/apis/transfers/v0/transfers.md index a0db763..ce89f05 100644 --- a/static/ru/apis/transfers/v0/transfers.md +++ b/static/ru/apis/transfers/v0/transfers.md @@ -382,3 +382,10 @@ "refName": "TransfersResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/apis/transfers/v0/transfers/index.md b/static/ru/apis/transfers/v0/transfers/index.md index a0db763..ce89f05 100644 --- a/static/ru/apis/transfers/v0/transfers/index.md +++ b/static/ru/apis/transfers/v0/transfers/index.md @@ -382,3 +382,10 @@ "refName": "TransfersResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/auth.md b/static/ru/auth.md index 2730547..b6f93a1 100644 --- a/static/ru/auth.md +++ b/static/ru/auth.md @@ -2,19 +2,21 @@ # Аутентификация и доступ -Один API-ключ FastNear работает и для [RPC](https://docs.fastnear.com/ru/rpc), и для [API-эндпоинтов](https://docs.fastnear.com/ru/api). Многие публичные чтения работают и без него, но когда ключ нужен, модель остаётся простой: используйте один и тот же ключ везде и передавайте его либо через заголовок `Authorization: Bearer`, либо как URL-параметр `?apiKey=`. +Один API-ключ FastNear работает и для [RPC](https://docs.fastnear.com/ru/rpc), и для [API-эндпоинтов](https://docs.fastnear.com/ru/api). Держите модель аутентификации простой: используйте один и тот же ключ везде и передавайте его либо через заголовок `Authorization: Bearer`, либо как URL-параметр `?apiKey=`. Та же модель действует и на обычных, и на архивных RPC-хостах. Хранение ключа в браузере для UI документации — это удобство документации, а не продовый шаблон. -Войдите на [dashboard.fastnear.com](https://dashboard.fastnear.com), чтобы получить ключ, и отправляйте его в каждом запросе одним из способов ниже. +Получите ключ в [FastNear Dashboard](https://dashboard.fastnear.com) и отправляйте его в каждом запросе одним из способов ниже. Страницы с интерактивными примерами также поддерживают `Copy example URL`, чтобы делиться уже заполненными запросами. Общие URL примеров выполняются автоматически при загрузке, когда в них есть состояние операции, а сохранённые API-ключи и токены никогда не включаются в такие общедоступные URL документации. ## Через заголовок Authorization ```bash +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + curl "https://rpc.mainnet.fastnear.com" \ - -H "Authorization: Bearer ${API_KEY}" \ + -H "Authorization: Bearer $FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` @@ -22,7 +24,16 @@ curl "https://rpc.mainnet.fastnear.com" \ ## Через URL-параметр `?apiKey=` ```bash -curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" \ +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + +curl "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/auth/index.md b/static/ru/auth/index.md index 2730547..b6f93a1 100644 --- a/static/ru/auth/index.md +++ b/static/ru/auth/index.md @@ -2,19 +2,21 @@ # Аутентификация и доступ -Один API-ключ FastNear работает и для [RPC](https://docs.fastnear.com/ru/rpc), и для [API-эндпоинтов](https://docs.fastnear.com/ru/api). Многие публичные чтения работают и без него, но когда ключ нужен, модель остаётся простой: используйте один и тот же ключ везде и передавайте его либо через заголовок `Authorization: Bearer`, либо как URL-параметр `?apiKey=`. +Один API-ключ FastNear работает и для [RPC](https://docs.fastnear.com/ru/rpc), и для [API-эндпоинтов](https://docs.fastnear.com/ru/api). Держите модель аутентификации простой: используйте один и тот же ключ везде и передавайте его либо через заголовок `Authorization: Bearer`, либо как URL-параметр `?apiKey=`. Та же модель действует и на обычных, и на архивных RPC-хостах. Хранение ключа в браузере для UI документации — это удобство документации, а не продовый шаблон. -Войдите на [dashboard.fastnear.com](https://dashboard.fastnear.com), чтобы получить ключ, и отправляйте его в каждом запросе одним из способов ниже. +Получите ключ в [FastNear Dashboard](https://dashboard.fastnear.com) и отправляйте его в каждом запросе одним из способов ниже. Страницы с интерактивными примерами также поддерживают `Copy example URL`, чтобы делиться уже заполненными запросами. Общие URL примеров выполняются автоматически при загрузке, когда в них есть состояние операции, а сохранённые API-ключи и токены никогда не включаются в такие общедоступные URL документации. ## Через заголовок Authorization ```bash +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + curl "https://rpc.mainnet.fastnear.com" \ - -H "Authorization: Bearer ${API_KEY}" \ + -H "Authorization: Bearer $FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` @@ -22,7 +24,16 @@ curl "https://rpc.mainnet.fastnear.com" \ ## Через URL-параметр `?apiKey=` ```bash -curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" \ +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + +curl "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv.md b/static/ru/fastdata/kv.md index 0f0a509..2ef9d8b 100644 --- a/static/ru/fastdata/kv.md +++ b/static/ru/fastdata/kv.md @@ -14,6 +14,37 @@ https://kv.main.fastnear.com https://kv.test.fastnear.com ``` +## Быстрый старт + +Если вы уже знаете один точный ключ, начните с последней индексированной строки и остановитесь, как только она ответит на вопрос. + +```bash +CURRENT_ACCOUNT_ID=social.near +PREDECESSOR_ID=james.near +KEY='graph/follow/sleet.near' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +ENCODED_KEY="$(jq -rn --arg key "$KEY" '$key | @uri')" + +curl -s "https://kv.main.fastnear.com/v0/latest/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + latest: ( + .entries[0] + | { + current_account_id, + predecessor_id, + block_height, + key, + value + } + ) + }' +``` + +Это самый узкий полезный KV-запрос: один точный ключ и одна последняя индексированная строка. Если следующий вопрос уже звучит как «как этот ключ менялся со временем?», переходите к [истории по точному ключу](https://docs.fastnear.com/ru/fastdata/kv/get-history-key) или к более подробным [примерам KV FastData](https://docs.fastnear.com/ru/fastdata/kv/examples). + ## Используйте этот API, когда - нужно последнее индексированное состояние по одному ключу или известному семейству ключей @@ -43,6 +74,10 @@ https://kv.test.fastnear.com - [Всё по `predecessor_id`](https://docs.fastnear.com/ru/fastdata/kv/all-by-predecessor) или [История по `predecessor_id`](https://docs.fastnear.com/ru/fastdata/kv/history-by-predecessor) — когда правильная область — `predecessor_id` - [Пакетный поиск по ключам](https://docs.fastnear.com/ru/fastdata/kv/multi) — когда уже известно несколько точных ключей +## Нужен сценарий? + +Используйте [примеры KV FastData](https://docs.fastnear.com/ru/fastdata/kv/examples) для практических примеров: поиска по точному ключу, истории ключей, анализа по `predecessor_id` и перехода к каноническому RPC. + ## Рабочий цикл по умолчанию 1. Выберите самую узкую область, подходящую под вопрос пользователя. @@ -74,3 +109,10 @@ https://kv.test.fastnear.com ### Мне нужны продуктовые балансы аккаунта, а не сырые строки «ключ–значение» Переходите на [FastNear API](https://docs.fastnear.com/ru/api). +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/all-by-predecessor.md b/static/ru/fastdata/kv/all-by-predecessor.md index 28bbce2..1dd24e5 100644 --- a/static/ru/fastdata/kv/all-by-predecessor.md +++ b/static/ru/fastdata/kv/all-by-predecessor.md @@ -207,3 +207,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/all-by-predecessor/index.md b/static/ru/fastdata/kv/all-by-predecessor/index.md index 28bbce2..1dd24e5 100644 --- a/static/ru/fastdata/kv/all-by-predecessor/index.md +++ b/static/ru/fastdata/kv/all-by-predecessor/index.md @@ -207,3 +207,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/examples.md b/static/ru/fastdata/kv/examples.md new file mode 100644 index 0000000..269d82d --- /dev/null +++ b/static/ru/fastdata/kv/examples.md @@ -0,0 +1,107 @@ +**Источник:** [https://docs.fastnear.com/ru/fastdata/kv/examples](https://docs.fastnear.com/ru/fastdata/kv/examples) + +## Примеры + +Все shell-примеры ниже работают на публичных KV FastData-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### Проверить один точный ключ и сразу посмотреть его историю + +Если контракт, `predecessor_id` и точный ключ уже известны, начинайте с узкого запроса. `latest` отвечает на вопрос о текущем состоянии, а `history` показывает, менялась ли именно эта строка со временем. + +```bash +CURRENT_ACCOUNT_ID=social.near +PREDECESSOR_ID=james.near +KEY='graph/follow/sleet.near' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +ENCODED_KEY="$(jq -rn --arg key "$KEY" '$key | @uri')" + +LATEST="$(curl -s "https://kv.main.fastnear.com/v0/latest/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}")" + +echo "$LATEST" | jq '{ + latest: ( + .entries[0] + | { + current_account_id, + predecessor_id, + block_height, + key, + value + } + ) +}' + +curl -s "https://kv.main.fastnear.com/v0/history/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{writes: [.entries[] | {block_height, value}]}' +``` + +Для точного ключа вроде этого follow-edge `latest` даёт текущее индексированное значение одной строкой, а `history` показывает, была ли запись однократной или переключалась со временем. Начинайте отсюда, когда путь в storage уже известен; расширяйтесь до выборок по `predecessor_id` только тогда, когда нужно не доказательство, а поиск. + +### Посмотреть индексированные записи одного `predecessor_id` и сузиться до изменившегося ключа + +`all-by-predecessor` возвращает последние индексированные записи одного аккаунта по каждому контракту, которого он касался. Выберите интересный ключ и прогоните его через `history`, чтобы увидеть, как эта строка менялась со временем. + +```bash +PREDECESSOR_ID=jemartel.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +FIRST="$(curl -s "https://kv.main.fastnear.com/v0/all/$PREDECESSOR_ID" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{"include_metadata":true,"limit":10}')" + +echo "$FIRST" | jq '{ + page_token, + entries: [.entries[] | {current_account_id, predecessor_id, block_height, key, value, tx_hash}] +}' +``` + +Для `jemartel.near` в выдаче смешиваются подтверждение идентичности `account_id` на `contextual.near` и серия добавлений `graph/follow/*` в тот же контракт. `tx_hash` в каждой строке — это прямой переход в [/tx/examples](https://docs.fastnear.com/ru/tx/examples#%D1%83-%D0%BC%D0%B5%D0%BD%D1%8F-%D0%BE%D0%B4%D0%B8%D0%BD-%D1%85%D0%B5%D1%88-%D1%82%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D0%B8-%D1%87%D1%82%D0%BE-%D0%BF%D1%80%D0%BE%D0%B8%D0%B7%D0%BE%D1%88%D0%BB%D0%BE), если нужна полная история транзакции за любой записью. + +Поднимите самую свежую строку и прогоните её через `history`: + +```bash +PREDECESSOR_ID=jemartel.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +FIRST="$(curl -s "https://kv.main.fastnear.com/v0/all/$PREDECESSOR_ID" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{"include_metadata":true,"limit":10}')" + +CURRENT_ACCOUNT_ID="$(echo "$FIRST" | jq -r '.entries[0].current_account_id')" +EXACT_KEY="$(echo "$FIRST" | jq -r '.entries[0].key')" +ENCODED_KEY="$(jq -rn --arg key "$EXACT_KEY" '$key | @uri')" + +curl -s "https://kv.main.fastnear.com/v0/history/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{entries: [.entries[] | {block_height, value}]}' +``` + +Для строки `account_id` `history` возвращает одну запись на блоке `185965311` со значением `"jemartel.near:mainnet"` — подтверждение идентичности держится, стабильно с того блока. KV сохраняет каждую запись одинаково: у тихого ключа — одна строка, у активного — много, форма та же, без агрегации. + +## Частые ошибки + +- Начинать с широких выборок по аккаунту или предшественнику, когда точный ключ уже известен. +- Использовать KV FastData, когда пользователю на самом деле нужны балансы или активы. +- Путать индексированную историю с точным текущим состоянием в цепочке. +- Переиспользовать токен пагинации или менять фильтры прямо во время просмотра. + +## Связанные страницы + +- [KV FastData API](https://docs.fastnear.com/ru/fastdata/kv) +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [FastNear API](https://docs.fastnear.com/ru/api) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/examples/index.md b/static/ru/fastdata/kv/examples/index.md new file mode 100644 index 0000000..269d82d --- /dev/null +++ b/static/ru/fastdata/kv/examples/index.md @@ -0,0 +1,107 @@ +**Источник:** [https://docs.fastnear.com/ru/fastdata/kv/examples](https://docs.fastnear.com/ru/fastdata/kv/examples) + +## Примеры + +Все shell-примеры ниже работают на публичных KV FastData-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### Проверить один точный ключ и сразу посмотреть его историю + +Если контракт, `predecessor_id` и точный ключ уже известны, начинайте с узкого запроса. `latest` отвечает на вопрос о текущем состоянии, а `history` показывает, менялась ли именно эта строка со временем. + +```bash +CURRENT_ACCOUNT_ID=social.near +PREDECESSOR_ID=james.near +KEY='graph/follow/sleet.near' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +ENCODED_KEY="$(jq -rn --arg key "$KEY" '$key | @uri')" + +LATEST="$(curl -s "https://kv.main.fastnear.com/v0/latest/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}")" + +echo "$LATEST" | jq '{ + latest: ( + .entries[0] + | { + current_account_id, + predecessor_id, + block_height, + key, + value + } + ) +}' + +curl -s "https://kv.main.fastnear.com/v0/history/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{writes: [.entries[] | {block_height, value}]}' +``` + +Для точного ключа вроде этого follow-edge `latest` даёт текущее индексированное значение одной строкой, а `history` показывает, была ли запись однократной или переключалась со временем. Начинайте отсюда, когда путь в storage уже известен; расширяйтесь до выборок по `predecessor_id` только тогда, когда нужно не доказательство, а поиск. + +### Посмотреть индексированные записи одного `predecessor_id` и сузиться до изменившегося ключа + +`all-by-predecessor` возвращает последние индексированные записи одного аккаунта по каждому контракту, которого он касался. Выберите интересный ключ и прогоните его через `history`, чтобы увидеть, как эта строка менялась со временем. + +```bash +PREDECESSOR_ID=jemartel.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +FIRST="$(curl -s "https://kv.main.fastnear.com/v0/all/$PREDECESSOR_ID" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{"include_metadata":true,"limit":10}')" + +echo "$FIRST" | jq '{ + page_token, + entries: [.entries[] | {current_account_id, predecessor_id, block_height, key, value, tx_hash}] +}' +``` + +Для `jemartel.near` в выдаче смешиваются подтверждение идентичности `account_id` на `contextual.near` и серия добавлений `graph/follow/*` в тот же контракт. `tx_hash` в каждой строке — это прямой переход в [/tx/examples](https://docs.fastnear.com/ru/tx/examples#%D1%83-%D0%BC%D0%B5%D0%BD%D1%8F-%D0%BE%D0%B4%D0%B8%D0%BD-%D1%85%D0%B5%D1%88-%D1%82%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D0%B8-%D1%87%D1%82%D0%BE-%D0%BF%D1%80%D0%BE%D0%B8%D0%B7%D0%BE%D1%88%D0%BB%D0%BE), если нужна полная история транзакции за любой записью. + +Поднимите самую свежую строку и прогоните её через `history`: + +```bash +PREDECESSOR_ID=jemartel.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +FIRST="$(curl -s "https://kv.main.fastnear.com/v0/all/$PREDECESSOR_ID" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{"include_metadata":true,"limit":10}')" + +CURRENT_ACCOUNT_ID="$(echo "$FIRST" | jq -r '.entries[0].current_account_id')" +EXACT_KEY="$(echo "$FIRST" | jq -r '.entries[0].key')" +ENCODED_KEY="$(jq -rn --arg key "$EXACT_KEY" '$key | @uri')" + +curl -s "https://kv.main.fastnear.com/v0/history/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{entries: [.entries[] | {block_height, value}]}' +``` + +Для строки `account_id` `history` возвращает одну запись на блоке `185965311` со значением `"jemartel.near:mainnet"` — подтверждение идентичности держится, стабильно с того блока. KV сохраняет каждую запись одинаково: у тихого ключа — одна строка, у активного — много, форма та же, без агрегации. + +## Частые ошибки + +- Начинать с широких выборок по аккаунту или предшественнику, когда точный ключ уже известен. +- Использовать KV FastData, когда пользователю на самом деле нужны балансы или активы. +- Путать индексированную историю с точным текущим состоянием в цепочке. +- Переиспользовать токен пагинации или менять фильтры прямо во время просмотра. + +## Связанные страницы + +- [KV FastData API](https://docs.fastnear.com/ru/fastdata/kv) +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [FastNear API](https://docs.fastnear.com/ru/api) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/get-history-key.md b/static/ru/fastdata/kv/get-history-key.md index 2879de1..abdc612 100644 --- a/static/ru/fastdata/kv/get-history-key.md +++ b/static/ru/fastdata/kv/get-history-key.md @@ -164,3 +164,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/get-history-key/index.md b/static/ru/fastdata/kv/get-history-key/index.md index 2879de1..abdc612 100644 --- a/static/ru/fastdata/kv/get-history-key/index.md +++ b/static/ru/fastdata/kv/get-history-key/index.md @@ -164,3 +164,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/get-latest-key.md b/static/ru/fastdata/kv/get-latest-key.md index 7608b13..51fd904 100644 --- a/static/ru/fastdata/kv/get-latest-key.md +++ b/static/ru/fastdata/kv/get-latest-key.md @@ -164,3 +164,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/get-latest-key/index.md b/static/ru/fastdata/kv/get-latest-key/index.md index 7608b13..51fd904 100644 --- a/static/ru/fastdata/kv/get-latest-key/index.md +++ b/static/ru/fastdata/kv/get-latest-key/index.md @@ -164,3 +164,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/history-by-account.md b/static/ru/fastdata/kv/history-by-account.md index 1e2fb55..c6c8f1a 100644 --- a/static/ru/fastdata/kv/history-by-account.md +++ b/static/ru/fastdata/kv/history-by-account.md @@ -239,3 +239,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/history-by-account/index.md b/static/ru/fastdata/kv/history-by-account/index.md index 1e2fb55..c6c8f1a 100644 --- a/static/ru/fastdata/kv/history-by-account/index.md +++ b/static/ru/fastdata/kv/history-by-account/index.md @@ -239,3 +239,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/history-by-key.md b/static/ru/fastdata/kv/history-by-key.md index c8c7b66..b31487e 100644 --- a/static/ru/fastdata/kv/history-by-key.md +++ b/static/ru/fastdata/kv/history-by-key.md @@ -225,3 +225,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/history-by-key/index.md b/static/ru/fastdata/kv/history-by-key/index.md index c8c7b66..b31487e 100644 --- a/static/ru/fastdata/kv/history-by-key/index.md +++ b/static/ru/fastdata/kv/history-by-key/index.md @@ -225,3 +225,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/history-by-predecessor.md b/static/ru/fastdata/kv/history-by-predecessor.md index dd78adc..e9e9a3e 100644 --- a/static/ru/fastdata/kv/history-by-predecessor.md +++ b/static/ru/fastdata/kv/history-by-predecessor.md @@ -242,3 +242,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/history-by-predecessor/index.md b/static/ru/fastdata/kv/history-by-predecessor/index.md index dd78adc..e9e9a3e 100644 --- a/static/ru/fastdata/kv/history-by-predecessor/index.md +++ b/static/ru/fastdata/kv/history-by-predecessor/index.md @@ -242,3 +242,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/index.md b/static/ru/fastdata/kv/index.md index 0f0a509..2ef9d8b 100644 --- a/static/ru/fastdata/kv/index.md +++ b/static/ru/fastdata/kv/index.md @@ -14,6 +14,37 @@ https://kv.main.fastnear.com https://kv.test.fastnear.com ``` +## Быстрый старт + +Если вы уже знаете один точный ключ, начните с последней индексированной строки и остановитесь, как только она ответит на вопрос. + +```bash +CURRENT_ACCOUNT_ID=social.near +PREDECESSOR_ID=james.near +KEY='graph/follow/sleet.near' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +ENCODED_KEY="$(jq -rn --arg key "$KEY" '$key | @uri')" + +curl -s "https://kv.main.fastnear.com/v0/latest/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + latest: ( + .entries[0] + | { + current_account_id, + predecessor_id, + block_height, + key, + value + } + ) + }' +``` + +Это самый узкий полезный KV-запрос: один точный ключ и одна последняя индексированная строка. Если следующий вопрос уже звучит как «как этот ключ менялся со временем?», переходите к [истории по точному ключу](https://docs.fastnear.com/ru/fastdata/kv/get-history-key) или к более подробным [примерам KV FastData](https://docs.fastnear.com/ru/fastdata/kv/examples). + ## Используйте этот API, когда - нужно последнее индексированное состояние по одному ключу или известному семейству ключей @@ -43,6 +74,10 @@ https://kv.test.fastnear.com - [Всё по `predecessor_id`](https://docs.fastnear.com/ru/fastdata/kv/all-by-predecessor) или [История по `predecessor_id`](https://docs.fastnear.com/ru/fastdata/kv/history-by-predecessor) — когда правильная область — `predecessor_id` - [Пакетный поиск по ключам](https://docs.fastnear.com/ru/fastdata/kv/multi) — когда уже известно несколько точных ключей +## Нужен сценарий? + +Используйте [примеры KV FastData](https://docs.fastnear.com/ru/fastdata/kv/examples) для практических примеров: поиска по точному ключу, истории ключей, анализа по `predecessor_id` и перехода к каноническому RPC. + ## Рабочий цикл по умолчанию 1. Выберите самую узкую область, подходящую под вопрос пользователя. @@ -74,3 +109,10 @@ https://kv.test.fastnear.com ### Мне нужны продуктовые балансы аккаунта, а не сырые строки «ключ–значение» Переходите на [FastNear API](https://docs.fastnear.com/ru/api). +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/latest-by-account.md b/static/ru/fastdata/kv/latest-by-account.md index 994407d..df2cc3a 100644 --- a/static/ru/fastdata/kv/latest-by-account.md +++ b/static/ru/fastdata/kv/latest-by-account.md @@ -227,3 +227,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/latest-by-account/index.md b/static/ru/fastdata/kv/latest-by-account/index.md index 994407d..df2cc3a 100644 --- a/static/ru/fastdata/kv/latest-by-account/index.md +++ b/static/ru/fastdata/kv/latest-by-account/index.md @@ -227,3 +227,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/latest-by-predecessor.md b/static/ru/fastdata/kv/latest-by-predecessor.md index f28cd37..06a5339 100644 --- a/static/ru/fastdata/kv/latest-by-predecessor.md +++ b/static/ru/fastdata/kv/latest-by-predecessor.md @@ -230,3 +230,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/latest-by-predecessor/index.md b/static/ru/fastdata/kv/latest-by-predecessor/index.md index f28cd37..06a5339 100644 --- a/static/ru/fastdata/kv/latest-by-predecessor/index.md +++ b/static/ru/fastdata/kv/latest-by-predecessor/index.md @@ -230,3 +230,10 @@ "refName": "ListResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/multi.md b/static/ru/fastdata/kv/multi.md index d9adb52..b31df34 100644 --- a/static/ru/fastdata/kv/multi.md +++ b/static/ru/fastdata/kv/multi.md @@ -198,3 +198,10 @@ "refName": "MultiResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/fastdata/kv/multi/index.md b/static/ru/fastdata/kv/multi/index.md index d9adb52..b31df34 100644 --- a/static/ru/fastdata/kv/multi/index.md +++ b/static/ru/fastdata/kv/multi/index.md @@ -198,3 +198,10 @@ "refName": "MultiResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/guides/llms.txt b/static/ru/guides/llms.txt index b2bad97..c330148 100644 --- a/static/ru/guides/llms.txt +++ b/static/ru/guides/llms.txt @@ -13,8 +13,10 @@ - [Справочник API](https://docs.fastnear.com/ru/api/reference.md): Руководство по маршрутизации между семействами FastNear REST API и их отличия от прямых методов JSON-RPC. - [Аутентификация и доступ](https://docs.fastnear.com/ru/auth.md): Один API-ключ FastNear работает и для RPC, и для REST API — отправляйте его через заголовок Authorization Bearer или как URL-параметр. - [KV FastData API](https://docs.fastnear.com/ru/fastdata/kv.md): Запросы только для чтения «ключ–значение» поверх FastData для сценариев с `predecessor_id`, аккаунтом, ключом и пакетным чтением. -- [NEAR Data API](https://docs.fastnear.com/ru/neardata.md): Кэшированные и архивные чтения по блокам для оптимистичных, финализированных и сценариев с перенаправлением. +- [Примеры KV FastData](https://docs.fastnear.com/ru/fastdata/kv/examples.md): Практические примеры KV FastData: точные ключи, scoped-записи, история ключа и переход к точному состоянию. +- [NEAR Data API](https://docs.fastnear.com/ru/neardata.md): Недавние чтения по блокам и шардам для мониторинга активности контракта, подтверждения оптимистичных наблюдений и проверки изменений на уровне шарда. - [Справочник RPC](https://docs.fastnear.com/ru/rpc.md): Прямой доступ по JSON-RPC к узлам NEAR от FastNear для запросов состояния, блоков, вызовов контрактов и отправки транзакций. +- [Примеры RPC](https://docs.fastnear.com/ru/rpc/examples.md): Практические примеры RPC: проверки состояния, инспекция блоков, чтение контрактов и отправка транзакций. - [API переводов](https://docs.fastnear.com/ru/transfers.md): История переводов NEAR и FT-токенов по аккаунтам для продуктовых лент и инструментов расследования. - [Транзакции API](https://docs.fastnear.com/ru/tx.md): Индексированные запросы по транзакциям, квитанциям, истории аккаунтов и истории блоков для FastNear. @@ -27,11 +29,18 @@ ## Другие гайды +- [Примеры API](https://docs.fastnear.com/ru/api/examples.md): Практические примеры FastNear API: поиск аккаунта по ключу, просмотр активов и классификация стейкинга. - [Руководство по интернационализации](https://docs.fastnear.com/ru/internationalization.md): Руководство для сопровождающих по добавлению локалей Docusaurus, локализованных оверлеев FastNear и безопасного для discovery процесса перевода. +- [Примеры NEAR Data](https://docs.fastnear.com/ru/neardata/examples.md): Практические примеры NEAR Data: живой мониторинг, optimistic-проверки и доказательство на уровне shard. - [redocly-config](https://docs.fastnear.com/ru/redocly-config.md): Исторические заметки о прежнем бэкенде Redocly и о том, где он всё ещё важен для проверки документации FastNear. +- [Примеры Transfers API](https://docs.fastnear.com/ru/transfers/examples.md): Практические примеры: фильтрация ленты переводов, пагинация и переход к истории транзакций. +- [Примеры Transactions](https://docs.fastnear.com/ru/tx/examples.md): Практические расследования транзакций: хеши, receipts, async-сбои и callback. +- [Berry Club: как читать живую доску и разбирать одну эпоху](https://docs.fastnear.com/ru/tx/examples/berry-club.md): Прочитайте живую доску Berry Club через RPC get_lines, а затем используйте Transactions API, чтобы восстановить одну более раннюю эпоху. +- [Расширенный поиск записи SocialDB](https://docs.fastnear.com/ru/tx/socialdb-proofs.md): Один короткий расширенный сценарий, который начинается с читаемого значения SocialDB и восстанавливает транзакцию записи за ним. ## Снапшоты - [Снапшоты для валидаторов](https://docs.fastnear.com/ru/snapshots.md): Пути загрузки снапшотов FastNear для подъёма и восстановления узлов NEAR. +- [Примеры snapshot](https://docs.fastnear.com/ru/snapshots/examples.md): Практические примеры восстановления узла: optimized, standard и archival. - [mainnet](https://docs.fastnear.com/ru/snapshots/mainnet.md): Скачайте RPC- и архивные снапшоты mainnet для быстрого развёртывания NEAR-инфраструктуры на базе FastNear. - [testnet](https://docs.fastnear.com/ru/snapshots/testnet.md): Скачайте RPC- и архивные снапшоты testnet для быстрого развёртывания NEAR-инфраструктуры на базе FastNear. diff --git a/static/ru/index.md b/static/ru/index.md index 85536f8..591bad6 100644 --- a/static/ru/index.md +++ b/static/ru/index.md @@ -20,7 +20,7 @@ URL-параметр ?apiKey=... - Сначала возьмите ключ — войдите на [dashboard.fastnear.com](https://dashboard.fastnear.com) через Google или email, получите бесплатные стартовые кредиты и подключайте месячную подписку или бессрочные резервные кредиты только тогда, когда понадобятся повышенные лимиты. + Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com) и используйте его во всех запросах к FastNear из одного и того же рабочего окружения. Быстрая маршрутизация @@ -97,7 +97,7 @@ Один API-ключ FastNear работает и для RPC, и для REST API. Ключи и оплата - [Dashboard](https://dashboard.fastnear.com) + [FastNear Dashboard](https://dashboard.fastnear.com) Войдите, создайте ключи и переходите на сценарии с более высокими лимитами, когда понадобится. Живые операции @@ -115,3 +115,10 @@ [Открыть хаб агентов](https://docs.fastnear.com/ru/agents) [Как выбрать поверхность](https://docs.fastnear.com/ru/agents/choosing-surfaces) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/internationalization.md b/static/ru/internationalization.md index 5cda7fa..65222a6 100644 --- a/static/ru/internationalization.md +++ b/static/ru/internationalization.md @@ -252,3 +252,10 @@ Playwright, relevance scoring и более тяжёлые редакционн 9. Добавьте браузерные smoke-checks только там, где локаль вносит новое поведение рантайма. Если идти по этому списку, следующие локали будут в основном редакционной задачей поверх уже готового фреймворка. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/internationalization/index.md b/static/ru/internationalization/index.md index 5cda7fa..65222a6 100644 --- a/static/ru/internationalization/index.md +++ b/static/ru/internationalization/index.md @@ -252,3 +252,10 @@ Playwright, relevance scoring и более тяжёлые редакционн 9. Добавьте браузерные smoke-checks только там, где локаль вносит новое поведение рантайма. Если идти по этому списку, следующие локали будут в основном редакционной задачей поверх уже готового фреймворка. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/llms-full.txt b/static/ru/llms-full.txt index ae95642..42962f5 100644 --- a/static/ru/llms-full.txt +++ b/static/ru/llms-full.txt @@ -31,7 +31,7 @@ AI-читабельные Markdown-копии авторских гайдов и URL-параметр ?apiKey=... - Сначала возьмите ключ — войдите на [dashboard.fastnear.com](https://dashboard.fastnear.com) через Google или email, получите бесплатные стартовые кредиты и подключайте месячную подписку или бессрочные резервные кредиты только тогда, когда понадобятся повышенные лимиты. + Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com) и используйте его во всех запросах к FastNear из одного и того же рабочего окружения. Быстрая маршрутизация @@ -108,7 +108,7 @@ AI-читабельные Markdown-копии авторских гайдов и Один API-ключ FastNear работает и для RPC, и для REST API. Ключи и оплата - [Dashboard](https://dashboard.fastnear.com) + [FastNear Dashboard](https://dashboard.fastnear.com) Войдите, создайте ключи и переходите на сценарии с более высокими лимитами, когда понадобится. Живые операции @@ -153,6 +153,7 @@ AI-читабельные Markdown-копии авторских гайдов и - Используйте индексированные API, когда пользователю нужен ответ в продуктовой форме — балансы, активы, история аккаунта или история переводов. - Используйте [Справочник RPC](https://docs.fastnear.com/ru/rpc), когда пользователю нужны канонические поля на уровне протокола, вызовы контрактов или отправка транзакций. +- Если вы используете размещённый JS-рантайм на [js.fastnear.com](https://js.fastnear.com), начинайте с низкоуровневых методов вроде `near.view`, `near.queryAccount` и `near.tx.*`, а к `near.recipes.*` обращайтесь только тогда, когда task helper действительно является самым коротким путём к ответу. - Используйте [NEAR Data API](https://docs.fastnear.com/ru/neardata), когда вопрос касается свежих оптимистичных или финализированных блоков и явного опроса. - Используйте [Снапшоты](https://docs.fastnear.com/ru/snapshots) для операторских сценариев, а не для чтения прикладных данных. - Один API-ключ FastNear работает и для RPC, и для API-эндпоинтов. @@ -226,20 +227,24 @@ AI-читабельные Markdown-копии авторских гайдов и ## Аутентифицируйтесь один раз, используйте везде -Публичные эндпоинты часто работают и без ключа. Добавьте ключ, если нужны повышенные лимиты, единая аутентифицированная модель или платные сценарии. Один и тот же ключ работает со всеми API FastNear выше, включая обычные и архивные RPC-хосты; передавайте его либо в HTTP-заголовке, либо в URL-параметре: +Начните с API-ключа FastNear и используйте его во всех API FastNear выше, включая обычные и архивные RPC-хосты. Передавайте его либо в HTTP-заголовке, либо в URL-параметре: ```bash title="Заголовок Authorization" +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + curl "https://rpc.mainnet.fastnear.com" \ - -H "Authorization: Bearer ${API_KEY}" \ + -H "Authorization: Bearer $FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` ```bash title="URL-параметр" -curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + +curl "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" ``` -Получить ключ: [dashboard.fastnear.com](https://dashboard.fastnear.com). Операционный режим для неинтерактивных сред: [Аутентификация для агентов](https://docs.fastnear.com/ru/agents/auth) — ключи должны жить в переменных окружения или менеджере секретов, а не в браузерном хранилище, логах чатов или промптах. Полный сценарий и детали заголовков: [Аутентификация и доступ](https://docs.fastnear.com/ru/auth). +Получите API-ключ в [FastNear Dashboard](https://dashboard.fastnear.com). Операционный режим для неинтерактивных сред: [Аутентификация для агентов](https://docs.fastnear.com/ru/agents/auth) — ключи должны жить в переменных окружения или менеджере секретов, а не в браузерном хранилище, логах чатов или промптах. Полный сценарий и детали заголовков: [Аутентификация и доступ](https://docs.fastnear.com/ru/auth). ## Как вынимать чистую документацию в промпт @@ -287,7 +292,7 @@ curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" Агенты должны аутентифицироваться в FastNear так же, как это делают продовые бэкенды. Не переносите браузерно-демонстрационный режим из UI документации в агента, воркера или среду автоматизации. -Один API-ключ FastNear работает во всех RPC и API-эндпоинтах. Многие публичные чтения работают и без ключа. Для агента важнее не само наличие аутентификации, а где живёт учётная запись, как она прикрепляется к запросам и как не допустить её утечки в промпты, логи или состояние браузера. +Один API-ключ FastNear работает во всех RPC и API-эндпоинтах. Для агента важнее не само наличие аутентификации, а где живёт учётная запись, как она прикрепляется к запросам и как не допустить её утечки в промпты, логи или состояние браузера. ## Если нужно только правило @@ -311,8 +316,8 @@ curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" | Способ | Используйте, когда... | Заметки | | --- | --- | --- | -| `Authorization: Bearer ${API_KEY}` | HTTP-клиентом или бэкендом управляете вы | Лучшее значение по умолчанию для агентов. Меньше шансов утечь в логи URL, аналитику или скопированные ссылки. | -| `?apiKey=${API_KEY}` | используется простой curl или система, которой сложно выставлять заголовки | Тоже допустимо, но URL обычно дальше путешествуют через логи и инструменты. Применяйте осознанно. | +| `Authorization: Bearer ${FASTNEAR_API_KEY}` | HTTP-клиентом или бэкендом управляете вы | Лучшее значение по умолчанию для агентов. Меньше шансов утечь в логи URL, аналитику или скопированные ссылки. | +| `?apiKey=${FASTNEAR_API_KEY}` | используется простой curl или система, которой сложно выставлять заголовки | Тоже допустимо, но URL обычно дальше путешествуют через логи и инструменты. Применяйте осознанно. | Если есть выбор — используйте заголовочную форму. @@ -343,13 +348,13 @@ const response = await fetch('https://rpc.mainnet.fastnear.com', { }); ``` -## Когда аутентификации не хватает +## Если в среде выполнения нет ключа -Многие публичные эндпоинты FastNear по-прежнему доступны на чтение без ключа. Если агент может ответить на вопрос пользователя через публичный трафик — делайте так. +Агенту по умолчанию стоит стартовать с настроенным API-ключом FastNear. Некоторые публичные чтения могут сработать и без него, но это не должно быть базовой рабочей моделью. -Когда ключ нужен для повышенных лимитов, платного доступа или аутентифицированного трафика: +Если в настроенной среде ключа пока нет: -- подскажите пользователю создать или забрать ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com) +- подскажите пользователю создать или забрать ключ в [FastNear Dashboard](https://dashboard.fastnear.com) - попросите настроить его в переменной окружения, менеджере секретов или конфигурации бэкенда - не просите вставлять сырой ключ в чат, чтобы агент «носил» его с собой @@ -967,6 +972,10 @@ https://test.api.fastnear.com - [V1 поиск по публичному ключу](https://docs.fastnear.com/ru/api/v1/public-key) — когда нужно определить аккаунт по ключу. - [V1 топ держателей FT](https://docs.fastnear.com/ru/api/v1/ft-top) — для представлений распределения токенов. +## Нужен сценарий? + +Используйте [примеры FastNear API](https://docs.fastnear.com/ru/api/examples) для практических примеров: сводки по аккаунтам, определения аккаунта по ключу и перехода к узким представлениям активов. + ## Устранение неполадок ### Мне нужно только одно низкоуровневое значение из состояния цепочки @@ -983,6 +992,212 @@ https://test.api.fastnear.com --- +## Примеры API + +- HTML-маршрут: https://docs.fastnear.com/ru/api/examples +- Markdown-маршрут: https://docs.fastnear.com/ru/api/examples.md + +**Источник:** [https://docs.fastnear.com/ru/api/examples](https://docs.fastnear.com/ru/api/examples) + +## Примеры + +Все shell-примеры ниже работают на публичных FastNear API-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### Свести один аккаунт за один вызов + +`/v1/account/{id}/full` — это агрегатор аккаунтов в FastNear API: один вызов собирает NEAR-состояние аккаунта, каждый FT-контракт, которого он касался, каждую NFT-коллекцию, которую он получил, и каждый валидаторский пул, в который делегировал. Если у вас уже есть `account_id`, это самый быстрый ответ на вопрос «что это за аккаунт?». + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + account_id, + near_balance_yocto: .state.balance, + ft_contracts: (.tokens | length), + nft_contracts: (.nfts | length), + staking_pool_contracts: (.pools | length) + }' +``` + +Для `root.near`: 150 FT-контрактов в списке, 102 NFT-коллекции, 2 валидаторских пула. Одни только счётчики контрактов говорят, что это оживлённый mainnet-аккаунт. Все примеры ниже погружаются в какую-то одну из этих поверхностей — начинайте отсюда, когда на руках только ID аккаунта. + +### Определить аккаунт по публичному ключу и сразу получить сводку + +Найдите, какому аккаунту принадлежит ключ, и прочитайте его активы за один следующий запрос. + +```bash +PUBLIC_KEY='ed25519:CCaThr3uokqnUs6Z5vVnaDcJdrfuTpYJHJWcAGubDjT' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +LOOKUP="$(curl -s "https://api.fastnear.com/v1/public_key/$(jq -rn --arg k "$PUBLIC_KEY" '$k | @uri')" \ + "${AUTH_HEADER[@]}")" + +echo "$LOOKUP" | jq '{matched: (.account_ids | length), account_ids}' + +ACCOUNT_ID="$(echo "$LOOKUP" | jq -r '.account_ids[0]')" + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq '{account_id, state, tokens: (.tokens|length), nfts: (.nfts|length), pools: (.pools|length)}' +``` + +Если `matched` больше 1, переключайтесь на [V1 Public Key Lookup All](https://docs.fastnear.com/ru/api/v1/public-key-all) и пройдитесь по каждому найденному аккаунту. + +### Сколько NEAR на этом аккаунте реально доступно к переводу? + +Состояние аккаунта NEAR делится на три ведра, которые UI кошельков обычно сливает в одно: `balance` — это свободная часть (не в стейкинге), `locked` — NEAR, привязанный к валидаторскому стейку или lockup-контракту, а `storage_bytes` подразумевает ещё отдельную долю, пришпиленную к trie по текущей ставке 10^19 yoctoNEAR за байт. Один pipeline над `/full` разводит их по полкам. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq ' + (.state.balance | tonumber) as $amount + | (.state.locked | tonumber) as $locked + | (.state.storage_bytes * 10000000000000000000) as $pinned + | 1e24 as $ynear + | { + account_id, + near: { + total_owned: (($amount + $locked) / $ynear), + unstaked: ($amount / $ynear), + stake_or_lockup: ($locked / $ynear), + pinned_to_storage: ($pinned / $ynear), + spendable: (($amount - $pinned) / $ynear) + } + }' +``` + +Для `root.near`: ~3914.67 NEAR всего, всё в свободной части, ~0.28677 NEAR закреплено за 28,677 байтами on-chain-состояния, ~3914.38 NEAR доступно к переводу. Новым аккаунтам это особенно заметно — свежесозданный именованный аккаунт ~182 байта «съедает» ~0.00182 NEAR под storage, и именно поэтому CLI-утилиты не дают отправить полный баланс. + +Наведите тот же pipeline на валидаторский пул вроде `astro-stakers.poolv1.near`, и пропорции перевернутся: ~730 тыс. свободных, ~27.68 млн в `locked`. Этот `locked` — собственный протокольный валидаторский стейк пула, а не средства делегатов (те учитываются внутри состояния контракта пула). Одно и то же поле означает разное на разных типах аккаунтов. + +jq считает в IEEE-754 double, поэтому NEAR-значения выше — только для отображения; для точной бухгалтерии сохраняйте сами yocto-строки. + +### Когда в этом аккаунте что-либо последний раз менялось? + +У каждой записи в массивах `tokens`, `nfts` и `pools` внутри `/full` есть собственное `last_update_block_height` — блок, в котором индексер последний раз видел изменение этой строки для этого аккаунта. Максимум по всем трём массивам даёт дешёвый сигнал «последняя активность» без похода в Transactions API. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/full" \ + "${AUTH_HEADER[@]}" \ + | jq ' + [ + (.tokens // [])[].last_update_block_height, + (.nfts // [])[].last_update_block_height, + (.pools // [])[].last_update_block_height + ] as $heights + | ($heights | map(select(. != null))) as $tracked + | { + account_id, + total_entries: ($heights | length), + tracked_entries: ($tracked | length), + most_recent_block: ($tracked | max), + oldest_tracked_block: ($tracked | min) + }' +``` + +Для `root.near` это возвращает 254 записи по FT-, NFT- и pool-контрактам, 158 с отслеживаемым блоком и самый свежий блок `194301659`. Этого уже достаточно, чтобы понять, что кошелёк живой, не заходя в историю транзакций. + +Это правильный вопрос для «был ли этот кошелёк недавно активен?» или «двигалось ли что-то после блока X?» — дёшево, один запрос, без истории транзакций. Чтобы достать саму транзакцию, вызвавшую последнее изменение, расширяйте поверхность до [Transactions API](https://docs.fastnear.com/ru/tx). Записи с `last_update_block_height: null` относятся ко времени до per-row-отслеживания индексером (обычно старые airdrops) и здесь игнорируются, а не считаются свежими. + +### Показать NFT-коллекции этого кошелька от конкретного издателя + +Имена аккаунтов на NEAR кодируют иерархию: `mint.sharddog.near` — это подаккаунт `sharddog.near`, который, в свою очередь, — подаккаунт `near`. Издатели, выпускающие несколько NFT-коллекций, обычно разворачивают каждую как отдельный подаккаунт, поэтому один фильтр по суффиксу над NFT-списком аккаунта вытаскивает всё опубликованное под одним деревом — без внешнего реестра коллекций. + +```bash +ACCOUNT_ID=root.near +PUBLISHER=sharddog.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/nft" \ + "${AUTH_HEADER[@]}" \ + | jq --arg publisher "$PUBLISHER" ' + ("." + $publisher) as $suffix + | { + account_id: .account_id, + publisher: $publisher, + collections: [ + .tokens[] + | select(.contract_id | endswith($suffix)) + | { + contract_id, + last_update_block_height, + status: (if .last_update_block_height == null then "dormant" else "active" end) + } + ] | sort_by(.last_update_block_height // 0) + }' +``` + +Для `root.near` и `sharddog.near` это возвращает четыре контракта-подаккаунта: `ndcconstellationnft`, `mint`, `harvestmoon` и `claim`. Только у `claim` есть ненулевой `last_update_block_height` (`131402024`), так что именно этот контракт явно менял позицию кошелька. Остальные — спящие, что типично для одноразовых drop-контрактов, в которые аккаунт что-то получил и больше не возвращался. + +Поменяйте `PUBLISHER` на любой аккаунт, чтобы сфокусировать фильтр на другом дереве издателя. + +### Показывает ли кошелёк прямой стейкинг, liquid staking-токены или оба варианта? + +Прямые позиции в пулах лежат на `/staking`; liquid staking-токены (stNEAR, LiNEAR и т. п.) лежат на `/ft` как обычные FT. Прочитайте оба эндпоинта и классифицируйте кошелёк — `root.near` оказывается `mixed`. + +```bash +ACCOUNT_ID=root.near +LIQUID_PROVIDERS_JSON='["meta-pool.near","lst.rhealab.near","linear-protocol.near"]' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +STAKING="$(curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/staking" \ + "${AUTH_HEADER[@]}")" +FT="$(curl -s "https://api.fastnear.com/v1/account/$ACCOUNT_ID/ft" \ + "${AUTH_HEADER[@]}")" + +jq -n \ + --argjson staking "$STAKING" \ + --argjson ft "$FT" \ + --argjson providers "$LIQUID_PROVIDERS_JSON" ' + ($staking.pools // []) as $direct + | (($ft.tokens // []) | map(select(.contract_id as $id | $providers | index($id)))) as $liquid + | { + classification: ( + if ($direct|length)>0 and ($liquid|length)>0 then "mixed" + elif ($direct|length)>0 then "direct_only" + elif ($liquid|length)>0 then "liquid_only" + else "no_visible_staking_position" end + ), + direct_pools: ($direct | map(.pool_id)), + liquid_tokens: ($liquid | map({contract_id, balance})) + }' +``` + +Классификатор знает только то, чему вы его научили — расширяйте `LIQUID_PROVIDERS_JSON` по мере появления новых liquid staking-продуктов и рассматривайте результат как наблюдательный, а не исчерпывающий. + +## Частые ошибки + +- Сразу идти в широкий снимок аккаунта, когда пользователя интересует только одна категория активов. +- Использовать FastNear API, хотя пользователю нужны точные поля RPC или права доступа. +- Оставаться на страницах сводок по аккаунту, когда вопрос уже стал вопросом об истории транзакций. + +## Связанные страницы + +- [FastNear API](https://docs.fastnear.com/ru/api) +- [API Reference](https://docs.fastnear.com/ru/api/reference) +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [Transactions API](https://docs.fastnear.com/ru/tx) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) + +--- + ## Справочник API - HTML-маршрут: https://docs.fastnear.com/ru/api/reference @@ -1050,19 +1265,21 @@ https://test.api.fastnear.com # Аутентификация и доступ -Один API-ключ FastNear работает и для [RPC](https://docs.fastnear.com/ru/rpc), и для [API-эндпоинтов](https://docs.fastnear.com/ru/api). Многие публичные чтения работают и без него, но когда ключ нужен, модель остаётся простой: используйте один и тот же ключ везде и передавайте его либо через заголовок `Authorization: Bearer`, либо как URL-параметр `?apiKey=`. +Один API-ключ FastNear работает и для [RPC](https://docs.fastnear.com/ru/rpc), и для [API-эндпоинтов](https://docs.fastnear.com/ru/api). Держите модель аутентификации простой: используйте один и тот же ключ везде и передавайте его либо через заголовок `Authorization: Bearer`, либо как URL-параметр `?apiKey=`. Та же модель действует и на обычных, и на архивных RPC-хостах. Хранение ключа в браузере для UI документации — это удобство документации, а не продовый шаблон. -Войдите на [dashboard.fastnear.com](https://dashboard.fastnear.com), чтобы получить ключ, и отправляйте его в каждом запросе одним из способов ниже. +Получите ключ в [FastNear Dashboard](https://dashboard.fastnear.com) и отправляйте его в каждом запросе одним из способов ниже. Страницы с интерактивными примерами также поддерживают `Copy example URL`, чтобы делиться уже заполненными запросами. Общие URL примеров выполняются автоматически при загрузке, когда в них есть состояние операции, а сохранённые API-ключи и токены никогда не включаются в такие общедоступные URL документации. ## Через заголовок Authorization ```bash +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + curl "https://rpc.mainnet.fastnear.com" \ - -H "Authorization: Bearer ${API_KEY}" \ + -H "Authorization: Bearer $FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` @@ -1070,7 +1287,9 @@ curl "https://rpc.mainnet.fastnear.com" \ ## Через URL-параметр `?apiKey=` ```bash -curl "https://rpc.mainnet.fastnear.com?apiKey=${API_KEY}" \ +: "${FASTNEAR_API_KEY:?Задайте FASTNEAR_API_KEY в окружении перед запуском примера.}" + +curl "https://rpc.mainnet.fastnear.com?apiKey=$FASTNEAR_API_KEY" \ -H "Content-Type: application/json" \ --data '{"method":"block","params":{"finality":"final"},"id":1,"jsonrpc":"2.0"}' ``` @@ -1098,6 +1317,37 @@ https://kv.main.fastnear.com https://kv.test.fastnear.com ``` +## Быстрый старт + +Если вы уже знаете один точный ключ, начните с последней индексированной строки и остановитесь, как только она ответит на вопрос. + +```bash +CURRENT_ACCOUNT_ID=social.near +PREDECESSOR_ID=james.near +KEY='graph/follow/sleet.near' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +ENCODED_KEY="$(jq -rn --arg key "$KEY" '$key | @uri')" + +curl -s "https://kv.main.fastnear.com/v0/latest/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + latest: ( + .entries[0] + | { + current_account_id, + predecessor_id, + block_height, + key, + value + } + ) + }' +``` + +Это самый узкий полезный KV-запрос: один точный ключ и одна последняя индексированная строка. Если следующий вопрос уже звучит как «как этот ключ менялся со временем?», переходите к [истории по точному ключу](https://docs.fastnear.com/ru/fastdata/kv/get-history-key) или к более подробным [примерам KV FastData](https://docs.fastnear.com/ru/fastdata/kv/examples). + ## Используйте этот API, когда - нужно последнее индексированное состояние по одному ключу или известному семейству ключей @@ -1127,6 +1377,10 @@ https://kv.test.fastnear.com - [Всё по `predecessor_id`](https://docs.fastnear.com/ru/fastdata/kv/all-by-predecessor) или [История по `predecessor_id`](https://docs.fastnear.com/ru/fastdata/kv/history-by-predecessor) — когда правильная область — `predecessor_id` - [Пакетный поиск по ключам](https://docs.fastnear.com/ru/fastdata/kv/multi) — когда уже известно несколько точных ключей +## Нужен сценарий? + +Используйте [примеры KV FastData](https://docs.fastnear.com/ru/fastdata/kv/examples) для практических примеров: поиска по точному ключу, истории ключей, анализа по `predecessor_id` и перехода к каноническому RPC. + ## Рабочий цикл по умолчанию 1. Выберите самую узкую область, подходящую под вопрос пользователя. @@ -1161,6 +1415,114 @@ https://kv.test.fastnear.com --- +## Примеры KV FastData + +- HTML-маршрут: https://docs.fastnear.com/ru/fastdata/kv/examples +- Markdown-маршрут: https://docs.fastnear.com/ru/fastdata/kv/examples.md + +**Источник:** [https://docs.fastnear.com/ru/fastdata/kv/examples](https://docs.fastnear.com/ru/fastdata/kv/examples) + +## Примеры + +Все shell-примеры ниже работают на публичных KV FastData-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### Проверить один точный ключ и сразу посмотреть его историю + +Если контракт, `predecessor_id` и точный ключ уже известны, начинайте с узкого запроса. `latest` отвечает на вопрос о текущем состоянии, а `history` показывает, менялась ли именно эта строка со временем. + +```bash +CURRENT_ACCOUNT_ID=social.near +PREDECESSOR_ID=james.near +KEY='graph/follow/sleet.near' +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +ENCODED_KEY="$(jq -rn --arg key "$KEY" '$key | @uri')" + +LATEST="$(curl -s "https://kv.main.fastnear.com/v0/latest/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}")" + +echo "$LATEST" | jq '{ + latest: ( + .entries[0] + | { + current_account_id, + predecessor_id, + block_height, + key, + value + } + ) +}' + +curl -s "https://kv.main.fastnear.com/v0/history/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{writes: [.entries[] | {block_height, value}]}' +``` + +Для точного ключа вроде этого follow-edge `latest` даёт текущее индексированное значение одной строкой, а `history` показывает, была ли запись однократной или переключалась со временем. Начинайте отсюда, когда путь в storage уже известен; расширяйтесь до выборок по `predecessor_id` только тогда, когда нужно не доказательство, а поиск. + +### Посмотреть индексированные записи одного `predecessor_id` и сузиться до изменившегося ключа + +`all-by-predecessor` возвращает последние индексированные записи одного аккаунта по каждому контракту, которого он касался. Выберите интересный ключ и прогоните его через `history`, чтобы увидеть, как эта строка менялась со временем. + +```bash +PREDECESSOR_ID=jemartel.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +FIRST="$(curl -s "https://kv.main.fastnear.com/v0/all/$PREDECESSOR_ID" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{"include_metadata":true,"limit":10}')" + +echo "$FIRST" | jq '{ + page_token, + entries: [.entries[] | {current_account_id, predecessor_id, block_height, key, value, tx_hash}] +}' +``` + +Для `jemartel.near` в выдаче смешиваются подтверждение идентичности `account_id` на `contextual.near` и серия добавлений `graph/follow/*` в тот же контракт. `tx_hash` в каждой строке — это прямой переход в [/tx/examples](https://docs.fastnear.com/ru/tx/examples#%D1%83-%D0%BC%D0%B5%D0%BD%D1%8F-%D0%BE%D0%B4%D0%B8%D0%BD-%D1%85%D0%B5%D1%88-%D1%82%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D0%B8-%D1%87%D1%82%D0%BE-%D0%BF%D1%80%D0%BE%D0%B8%D0%B7%D0%BE%D1%88%D0%BB%D0%BE), если нужна полная история транзакции за любой записью. + +Поднимите самую свежую строку и прогоните её через `history`: + +```bash +PREDECESSOR_ID=jemartel.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +FIRST="$(curl -s "https://kv.main.fastnear.com/v0/all/$PREDECESSOR_ID" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{"include_metadata":true,"limit":10}')" + +CURRENT_ACCOUNT_ID="$(echo "$FIRST" | jq -r '.entries[0].current_account_id')" +EXACT_KEY="$(echo "$FIRST" | jq -r '.entries[0].key')" +ENCODED_KEY="$(jq -rn --arg key "$EXACT_KEY" '$key | @uri')" + +curl -s "https://kv.main.fastnear.com/v0/history/$CURRENT_ACCOUNT_ID/$PREDECESSOR_ID/$ENCODED_KEY" \ + "${AUTH_HEADER[@]}" \ + | jq '{entries: [.entries[] | {block_height, value}]}' +``` + +Для строки `account_id` `history` возвращает одну запись на блоке `185965311` со значением `"jemartel.near:mainnet"` — подтверждение идентичности держится, стабильно с того блока. KV сохраняет каждую запись одинаково: у тихого ключа — одна строка, у активного — много, форма та же, без агрегации. + +## Частые ошибки + +- Начинать с широких выборок по аккаунту или предшественнику, когда точный ключ уже известен. +- Использовать KV FastData, когда пользователю на самом деле нужны балансы или активы. +- Путать индексированную историю с точным текущим состоянием в цепочке. +- Переиспользовать токен пагинации или менять фильтры прямо во время просмотра. + +## Связанные страницы + +- [KV FastData API](https://docs.fastnear.com/ru/fastdata/kv) +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [FastNear API](https://docs.fastnear.com/ru/api) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) + +--- + ## Руководство по интернационализации - HTML-маршрут: https://docs.fastnear.com/ru/internationalization @@ -1432,7 +1794,7 @@ Playwright, relevance scoring и более тяжёлые редакционн # NEAR Data API -NEAR Data API — это поверхность для чтения данных почти в реальном времени, а также по семействам блоков. Используйте её, когда нужны свежие срезы блоков, вспомогательные маршруты с перенаправлением или недавние финализированные и оптимистичные чтения, но без позиционирования продукта как потокового сервиса. +NEAR Data API — это поверхность для недавних блоков и шардов. Используйте её, когда нужны свежие срезы блоков, мониторинг активности контракта, вспомогательные маршруты с перенаправлением или сравнение оптимистичных и финализированных чтений без превращения продукта в потоковый API. ## Базовые URL @@ -1447,8 +1809,9 @@ https://testnet.neardata.xyz ## Лучше всего подходит для - опроса недавних финализированных и оптимистичных блоков; -- вспомогательных маршрутов по блокам и сценариев с перенаправлением; -- лёгких проверок свежести данных и мониторинга. +- обнаружения того, появился ли живой контракт в недавнем блоке и изменил ли он состояние; +- сравнения оптимистичного сигнала с финализированным подтверждением; +- проверки одного недавнего шарда, когда уже известно, какой блок важен. ## Когда его не стоит использовать @@ -1463,9 +1826,14 @@ https://testnet.neardata.xyz ## С чего обычно начинают -- [Оптимистичный блок](https://docs.fastnear.com/ru/neardata/block-optimistic) — для самого свежего опроса блоков. -- [Финализированный блок по высоте](https://docs.fastnear.com/ru/neardata/block) и [Заголовки блока](https://docs.fastnear.com/ru/neardata/block-headers) — для запросов по финализированным блокам. -- [Перенаправление на последний финализированный блок](https://docs.fastnear.com/ru/neardata/last-block-final) и [Перенаправление на последний оптимистичный блок](https://docs.fastnear.com/ru/neardata/last-block-optimistic) — когда нужны вспомогательные маршруты с перенаправлением. +- [Перенаправление на последний финализированный блок](https://docs.fastnear.com/ru/neardata/last-block-final) и [Перенаправление на последний оптимистичный блок](https://docs.fastnear.com/ru/neardata/last-block-optimistic) — когда нужно быстро узнать самый новый недавний блок. +- [Финализированный блок по высоте](https://docs.fastnear.com/ru/neardata/block) — когда нужен один недавний гидратированный блок с уже приложенными данными по шардам. +- [Шард блока](https://docs.fastnear.com/ru/neardata/block-shard) — когда недавний блок уже показал нужный шард и его надо разобрать глубже. +- [Заголовки блока](https://docs.fastnear.com/ru/neardata/block-headers) — когда важнее движение головы цепочки и финальности, а не широкий блоковый документ. + +## Нужен сценарий? + +Используйте [примеры NEAR Data API](https://docs.fastnear.com/ru/neardata/examples) для практических примеров: обнаружения активности контракта, сравнения оптимистичных и финализированных наблюдений, а также проверки изменений на уровне шарда. ## Устранение неполадок @@ -1483,6 +1851,154 @@ https://testnet.neardata.xyz --- +## Примеры NEAR Data + +- HTML-маршрут: https://docs.fastnear.com/ru/neardata/examples +- Markdown-маршрут: https://docs.fastnear.com/ru/neardata/examples.md + +**Источник:** [https://docs.fastnear.com/ru/neardata/examples](https://docs.fastnear.com/ru/neardata/examples) + +## Примеры + +NEAR Data возвращает каждый блок полностью гидратированным одним JSON-документом — header плюс per-shard chunks, receipts, результаты исполнения и state changes, — так что один `curl` уже даёт всё необходимое, чтобы отфильтровать нужный контракт без второго запроса. + +Все shell-примеры ниже работают на публичных NEAR Data-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### На каком блоке NEAR сейчас? + +`/v0/last_block/final` отдаёт 302-редирект на текущий финализированный блок. Прежде чем фильтровать по конкретному контракту, полезно увидеть, как выглядит один блок на уровне протокола: транзакции приходят с разбивкой по shard, поэтому общее число транзакций в блоке — это сумма по shards, а не одно поле верхнего уровня. + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + height: .block.header.height, + timestamp_nanosec: .block.header.timestamp_nanosec, + txs_per_shard: [.shards[] | {shard_id, tx_count: (.chunk.transactions | length)}], + total_txs: ([.shards[].chunk.transactions[]?] | length) + }' +``` + +Живой блок показывает 9 shards и горсть транзакций, распределённых по ним — большинство shards в любом блоке пустые, а активность концентрируется на тех shards, где живут загруженные контракты. `timestamp_nanosec` — это Unix-время в наносекундах (делите на 1e9, чтобы получить секунды). С этим одним вызовом у вас уже есть всё необходимое для дальнейшего копания — примеры фильтрации ниже просто применяют jq к тому же ответу. + +### Был ли мой контракт затронут в последнем финализированном блоке? + +`/v0/last_block/final` отдаёт 302-редирект на текущий финализированный блок. Контракт может проявиться либо в `transactions` chunk (когда он `receiver_id`), либо в `receipts` (когда прилетает cross-shard-вызов), поэтому один проход jq по shards покрывает оба случая. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" \ + | jq --arg contract "$TARGET_CONTRACT" '{ + height: .block.header.height, + contract: $contract, + touched_shards: [ + .shards[] | { + shard_id, + txs: [.chunk.transactions[]? | select(.transaction.receiver_id == $contract) | .transaction.hash], + receipts: [.chunk.receipts[]? | select(.receiver_id == $contract) | .receipt_id] + } | select((.txs | length) + (.receipts | length) > 0) + ] + }' +``` + +`touched_shards: []` — полный ответ для тихого блока. Непустой список называет shards, где контракт появился, и отдаёт конкретные `tx`-хеши или `receipt_id` — передавайте хеш в [Transactions API](https://docs.fastnear.com/ru/tx), когда нужна человекочитаемая история. Receipts без парных `txs` — это нормально: cross-contract-вызов приходит как incoming receipt в этом блоке, даже если исходная транзакция была раньше. + +### Увидел ли я активность в optimistic-режиме, и догнала ли её finality? + +Optimistic-блоки ходят по `/v0/block_opt/{height}` примерно на секунду впереди `/v0/block/{height}`. Цикл мониторинга может действовать по optimistic-сигналу и ожидать, что тот же ответ придёт на финализированный эндпоинт через один блок — если только стресс сети не расширит разрыв, и тогда финализированный fetch вернёт `null`, а вы подождёте. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +count_touches() { + jq --arg contract "$1" ' + [.shards[] + | ([.chunk.transactions[]? | select(.transaction.receiver_id == $contract)] | length) + + ([.chunk.receipts[]? | select(.receiver_id == $contract)] | length)] + | add // 0' +} + +OPT_LOCATION="$( + curl -s -D - -o /dev/null "${AUTH_HEADER[@]}" "https://mainnet.neardata.xyz/v0/last_block/optimistic" \ + | awk 'tolower($1) == "location:" {print $2}' | tr -d '\r' +)" +OPT_HEIGHT="${OPT_LOCATION##*/}" + +echo "optimistic @ $OPT_HEIGHT: $(curl -s "https://mainnet.neardata.xyz$OPT_LOCATION" \ + "${AUTH_HEADER[@]}" | count_touches "$TARGET_CONTRACT") touches" +FINAL="$(curl -s "https://mainnet.neardata.xyz/v0/block/$OPT_HEIGHT" \ + "${AUTH_HEADER[@]}")" +if [ "$(printf '%s' "$FINAL" | jq 'type')" = '"null"' ]; then + echo "finalized @ $OPT_HEIGHT: not caught up yet" +else + echo "finalized @ $OPT_HEIGHT: $(printf '%s' "$FINAL" | count_touches "$TARGET_CONTRACT") touches" +fi +``` + +На здоровом mainnet оба счётчика совпадают в пределах секунды. Ценность — в самом шаблоне: optimistic-поток даёт ответ, на который можно реагировать сразу, а финализированный приходит через блок как надёжное подтверждение. + +### Какой shard действительно изменил состояние моего контракта? + +В большинстве финализированных блоков нет мутации состояния ни для одного конкретного контракта — активность разрежена и привязана к shard. Идите назад от финализированной головы, пока состояние контракта реально не изменится, и откройте этот shard для payload мутации. Вызов уровня блока говорит, *на каком* shard это случилось; вызов уровня shard — *как*. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +HEAD="$(curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" | jq '.block.header.height')" +FOUND_HEIGHT="" +FOUND_SHARD="" + +for OFFSET in $(seq 0 15); do + H=$((HEAD - OFFSET)) + SHARD="$(curl -s "https://mainnet.neardata.xyz/v0/block/$H" \ + "${AUTH_HEADER[@]}" \ + | jq -r --arg contract "$TARGET_CONTRACT" ' + .shards[] + | select([.state_changes[]? | select(.change.account_id? == $contract)] | length > 0) + | .shard_id + ' | head -1)" + if [ -n "$SHARD" ]; then + FOUND_HEIGHT=$H; FOUND_SHARD=$SHARD + break + fi +done + +if [ -z "$FOUND_HEIGHT" ]; then + echo "no state mutation for $TARGET_CONTRACT in the last 16 finalized blocks" +else + curl -s "https://mainnet.neardata.xyz/v0/block/$FOUND_HEIGHT/shard/$FOUND_SHARD" \ + "${AUTH_HEADER[@]}" \ + | jq --arg contract "$TARGET_CONTRACT" --argjson height "$FOUND_HEIGHT" --argjson shard_id "$FOUND_SHARD" '{ + height: $height, + shard_id: $shard_id, + state_changes: [.state_changes[] | select(.change.account_id? == $contract) | {type, cause: (.cause | keys[0])}][0:3], + execution_outcomes: [.receipt_execution_outcomes[] | select(.execution_outcome.outcome.executor_id == $contract) | {receipt_id: .execution_outcome.id, status: (.execution_outcome.outcome.status | keys[0])}][0:3] + }' +fi +``` + +На mainnet `intents.near` живёт на shard 7, поэтому обход назад обычно попадает в цель за несколько блоков. Payload shard называет конкретные типы state-change (`account_update`, `data_update` и т. п.) и результаты receipt, которые их породили, — shard-локальное доказательство без догадок. Для менее активных контрактов расширьте диапазон `OFFSET`. + +## Когда расширить поверхность + +- Используйте [Transactions API](https://docs.fastnear.com/ru/tx), когда у вас уже есть `tx_hash` и нужна человекочитаемая история транзакции. +- Используйте [RPC Reference](https://docs.fastnear.com/ru/rpc), когда следующий вопрос касается точной протокольной семантики receipt или блока. +- Используйте [Block Headers](https://docs.fastnear.com/ru/neardata/block-headers), когда нужна только динамика head/finality, а не проверка contract-touch. + +--- + ## redocly-config - HTML-маршрут: https://docs.fastnear.com/ru/redocly-config @@ -1583,6 +2099,10 @@ https://archival-rpc.testnet.fastnear.com - [`send_tx`](https://docs.fastnear.com/ru/rpc/transaction/send-tx) — отправка транзакций; [`tx`](https://docs.fastnear.com/ru/rpc/transaction/tx-status) — статус исполнения. - [`validators`](https://docs.fastnear.com/ru/rpc/validators/validators-current) — валидаторы текущей эпохи. +## Нужен сценарий? + +Используйте [примеры RPC](https://docs.fastnear.com/ru/rpc/examples) для практических примеров: точных проверок состояния, анализа блоков, view-вызовов контрактов и отправки транзакций с подтверждением. + ## Используйте RPC, когда - нужны канонические формы запросов и ответов из протокола; @@ -1627,6 +2147,310 @@ https://archival-rpc.testnet.fastnear.com --- +## Примеры RPC + +- HTML-маршрут: https://docs.fastnear.com/ru/rpc/examples +- Markdown-маршрут: https://docs.fastnear.com/ru/rpc/examples.md + +**Источник:** [https://docs.fastnear.com/ru/rpc/examples](https://docs.fastnear.com/ru/rpc/examples) + +# Примеры RPC + +Начинайте с RPC-метода, который отвечает на вопрос. Используйте `tx`, чтобы отследить включение и финальность по хешу транзакции, и расширяйте поверхность только когда нужны дерево receipts, сырой state или трассировка на уровне shard. + +Все shell-примеры ниже работают на публичных RPC-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +## Состояние аккаунта + +### Показать баланс и storage аккаунта на finality + +`view_account` — канонический RPC-запрос для текущего состояния аккаунта. Один вызов возвращает свободный баланс, сумму, заблокированную в валидаторском стейке или lockup-контракте, использованное storage и блок, на котором было сделано чтение. `finality: "final"` гарантирует, что вы читаете стабильное состояние, а не optimistic-представление. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.mainnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_account",account_id:$account_id,finality:"final"} + }')" \ + | jq '.result | {amount, locked, storage_usage, block_height, block_hash}' +``` + +Для `root.near` это возвращает `amount` (yoctoNEAR в свободной части), `locked: "0"` (ничего в валидаторском стейке или lockup-контракте) и `storage_usage: 28677` — примерно 28.7 КБ on-chain-состояния. Пара `block_height`/`block_hash` фиксирует точку чтения; чтобы прочитать несколько аккаунтов *на одном и том же* блоке, переиспользуйте возвращённый `block_hash` как `block_id` в последующих запросах. + +## Включение транзакции и финальность + +### Отследить транзакцию от хеша до финальности + +Есть tx hash? Опрашивайте `tx` с минимальным порогом `wait_until`, который отвечает на ваш вопрос. + +```bash +TX_HASH=CVyG2xLJ6fuKCtULAxMnWTh2GL5ey2UUiTcgYT3M6Pow +SIGNER_ACCOUNT_ID=mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://archival-rpc.testnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" --arg signer_id "$SIGNER_ACCOUNT_ID" '{ + jsonrpc: "2.0", id: "fastnear", method: "tx", + params: {tx_hash: $tx_hash, sender_account_id: $signer_id, wait_until: "INCLUDED"} + }')" \ + | jq '{ + asked: "INCLUDED", + final_execution_status: .result.final_execution_status, + status_class: (.result.status | keys[0]), + receipts_outcome_count: (.result.receipts_outcome | length) + }' +``` + +Для зафиксированной исторической транзакции (1-yocto self-transfer от `mike.testnet`) ответ возвращается как `FINAL`, хотя мы спрашивали `INCLUDED`. Правило такое: **`wait_until` — это минимальный порог, а не целевой**. Узел возвращает тот этап, которого транзакция действительно достигла: для исторической всегда `FINAL`; для полётной выбирайте `INCLUDED`, когда достаточно включения и нужен самый ранний возврат, или `FINAL`, когда реальный вопрос звучит «завершилась ли?». + +Два перехода отсюда: + +- **Отправляете в реальном времени?** [`broadcast_tx_async`](https://docs.fastnear.com/ru/rpc/transaction/broadcast-tx-async) возвращает хеш сразу после того, как узел принял payload — отслеживайте отдельно через `tx`. [`send_tx`](https://docs.fastnear.com/ru/rpc/transaction/send-tx) одновременно отправляет и блокируется на выбранном `wait_until` в одном запросе. +- **Нужно дерево receipts, а не только outcome?** `tx` уже включает `receipts_outcome`; расширяйте поверхность до [`EXPERIMENTAL_tx_status`](https://docs.fastnear.com/ru/rpc/transaction/experimental-tx-status) только тогда, когда дополнительно нужны сырые записи receipts. + +## Инспекция блока на tip + +### Описать первый action первой транзакции на текущем tip + +Блок NEAR — это header поверх N shard chunks, а не плоский список транзакций. `block` возвращает headers chunks; сами транзакции лежат уровнем ниже, внутри `chunk`. Шортката `block → tx` нет — блок не несёт хешей транзакций, поэтому `tx` (которому нужен hash) в этой цепочке не участвует. Канонический проход — `status` → `block` → `chunk`, пропуская пустые chunks по дороге. Большинство chunks в tip-блоке пустые — их `tx_root` равен сентинелу `11111111111111111111111111111111`, поэтому селектору нужен фильтр. + +```bash +EMPTY_TX_ROOT=11111111111111111111111111111111 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +BLOCK_HASH="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data '{"jsonrpc":"2.0","id":"fastnear","method":"status","params":[]}' \ + | jq -r '.result.sync_info.latest_block_hash')" + +CHUNK_HASH="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg block_hash "$BLOCK_HASH" '{ + jsonrpc:"2.0",id:"fastnear",method:"block",params:{block_id:$block_hash} + }')" \ + | jq -r --arg empty "$EMPTY_TX_ROOT" ' + first(.result.chunks[] | select(.tx_root != $empty) | .chunk_hash) // empty')" + +if [ -z "$CHUNK_HASH" ]; then + echo "tip block had no transactions in any chunk — rerun on the next head" +else + curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg chunk_hash "$CHUNK_HASH" '{ + jsonrpc:"2.0",id:"fastnear",method:"chunk",params:{chunk_id:$chunk_hash} + }')" \ + | jq '{ + chunk_shard: .result.header.shard_id, + chunk_height: .result.header.height_included, + first_tx: { + hash: .result.transactions[0].hash, + signer_id: .result.transactions[0].signer_id, + receiver_id: .result.transactions[0].receiver_id + }, + first_action: ( + .result.transactions[0].actions[0] as $a + | if ($a | type) == "string" then {kind: $a} + elif $a.FunctionCall then {kind: "FunctionCall", method_name: $a.FunctionCall.method_name} + else {kind: ($a | keys[0])} end + ) + }' +fi +``` + +Живой запуск возвращает первый chunk текущего tip, первую транзакцию и первый action — часто это `FunctionCall` на контракте моста или tg-бота (mainnet активен). Tip-блок может быть валидным и при этом не содержать транзакций ни в одном chunk — поэтому ветка с пустым результатом остаётся; это честный ответ для тихого момента сети. + +## Механика аккаунтов и ключей + +### Определить function-call-ключи, которые стоит удалить + +Каждый кошелёк, шлюз и dapp-сессия, в которую вы заходите, обычно оставляет за собой function-call-ключ. Большинством из них вы больше никогда не воспользуетесь. `view_access_key_list` возвращает все ключи аккаунта; структура nonce показывает, какие из них устарели. + +Новые ключи стартуют с `block_height * 10^6`, и значение инкрементируется на единицу за каждую транзакцию, которую ключ подписывает, поэтому: + +- `nonce / 10^6` → блок, в котором ключ был добавлен +- `nonce % 10^6` → сколько раз ключ был использован + +Любой ключ с `tx_count: 0` был создан и ни разу не использовался — самый очевидный кандидат на очистку. Следующий по порядку — ключи, заскоупленные на контракт, с которым вы больше не работаете. Фильтр ниже сужает до `social.near`, но чтобы аудитировать другой контракт, меняется только строка `RECEIVER_ID`. + +```bash +ACCOUNT_ID=root.near +RECEIVER_ID=social.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.mainnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_access_key_list",account_id:$account_id,finality:"final"} + }')" \ + | jq --arg receiver "$RECEIVER_ID" ' + { + total_keys: (.result.keys | length), + fcks_for_receiver: [ + .result.keys[] + | select((.access_key.permission | type) == "object") + | select(.access_key.permission.FunctionCall.receiver_id == $receiver) + | { + public_key, + added_at_block: (.access_key.nonce / 1000000 | floor), + tx_count: (.access_key.nonce % 1000000), + method_names: (.access_key.permission.FunctionCall.method_names | if . == [] then "ANY" else . end), + allowance: (.access_key.permission.FunctionCall.allowance // "unlimited") + } + ] | sort_by(.tx_count) + }' +``` + +Для `root.near` это возвращает 235 ключей всего, включая 34 function-call-ключа на `social.near`; 21 из них были созданы и ни разу не использовались (`tx_count: 0`) и потому являются прямыми кандидатами на удаление. `method_names: "ANY"` означает, что ключ может вызвать любой метод на `social.near`; сужение до списка вида `["find_grants", "insert_grant", "delete_grant"]` означает, что ключ был заскоуплен на write-поверхность одного dapp. + +Чтобы удалить такой ключ, подпишите action `DeleteKey` **full-access**-ключом (function-call-ключ не может авторизовать `DeleteKey`) и отправьте через [`send_tx`](https://docs.fastnear.com/ru/rpc/transaction/send-tx). Повторный запуск того же запроса подтвердит, что ключа больше нет. + +## Чтение контрактов и сырой state + +### Прочитать storage контракта, не запуская его + +View-метод вроде `get_num` всё равно заставляет узел загрузить wasm-контракта и выполнить его. Если ключ storage уже известен, `view_state` возвращает сырые сериализованные байты напрямую — без исполнения и без зависимости от того, выставил ли контракт getter для этого поля вообще. + +Контракты на `near-sdk-rs` хранят верхнеуровневую `#[near_bindgen]`-структуру под ключом `STATE`. Передайте `STATE` как `prefix_base64` (`U1RBVEU=` — это base64 тех же четырёх ASCII-байт), и узел вернёт сериализованное значение. + +```bash +CONTRACT_ID=counter.near-examples.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +RAW_B64="$(curl -s "https://rpc.testnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg contract "$CONTRACT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_state",account_id:$contract,prefix_base64:"U1RBVEU=",finality:"final"} + }')" \ + | jq -r '.result.values[0].value')" + +DECODED_I8="$(python3 -c "import base64; print(int.from_bytes(base64.b64decode('$RAW_B64'),'little',signed=True))")" + +jq -n --arg raw "$RAW_B64" --argjson val "$DECODED_I8" '{raw_bytes_base64: $raw, decoded_i8: $val}' +``` + +Для живого counter это возвращает `"CQ=="` — один байт `0x09`, декодируется как signed i8 в `9`. Это то же число, которое вернул бы `get_num`, только прочитанное прямо из trie без запуска кода контракта. `signed=True` важен: отрицательный counter сериализовался бы как `"/w=="` (байт `0xff` → i8 `-1`, а не u8 `255`). + +Тянитесь к `view_state`, когда контракт не выставляет view-метод для нужных данных или когда нужна семья ключей, которую контракт не публикует. Для большинства чтений `call_function` всё равно требует меньше церемоний. Если вопрос становится историческим, а не текущим, расширяйте поверхность до [KV FastData API](https://docs.fastnear.com/ru/fastdata/kv). + +## NEAR Social и точные чтения BOS + +Оставайтесь на точных чтениях SocialDB и on-chain-проверках готовности — пока вопрос не станет историческим. + +### Может ли этот аккаунт прямо сейчас публиковать в NEAR Social? + +`social.near` знает две вещи, о которых UI кошелька может только догадываться: сколько storage осталось у каждого аккаунта и разрешена ли делегированному signer запись под этим аккаунтом. Два view-вызова сворачивают вопрос готовности к одному boolean. + +```bash +ACCOUNT_ID=root.near # account you're writing under +SIGNER_ACCOUNT_ID=root.near # account signing the transaction +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +STORAGE_ARGS_B64="$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id:$account_id}' | base64 | tr -d '\n')" + +STORAGE="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$STORAGE_ARGS_B64" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"get_account_storage",args_base64:$args,finality:"final"} + }')" \ + | jq '.result.result | implode | fromjson')" + +if [ "$SIGNER_ACCOUNT_ID" = "$ACCOUNT_ID" ]; then + PERMISSION=true +else + PERM_ARGS_B64="$(jq -nc --arg pred "$SIGNER_ACCOUNT_ID" --arg key "$ACCOUNT_ID" '{predecessor_id:$pred,key:$key}' | base64 | tr -d '\n')" + PERMISSION="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$PERM_ARGS_B64" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"is_write_permission_granted",args_base64:$args,finality:"final"} + }')" \ + | jq '.result.result | implode | fromjson')" +fi + +jq -n --argjson storage "$STORAGE" --argjson permission "$PERMISSION" \ + --arg account_id "$ACCOUNT_ID" --arg signer "$SIGNER_ACCOUNT_ID" '{ + account_id: $account_id, + signer_account_id: $signer, + storage: $storage, + permission_granted: $permission, + ready_to_publish: (($storage.available_bytes // 0) > 0 and $permission) + }' +``` + +Для `root.near`, подписывающего под собой, это возвращает `storage: {used_bytes: 136245, available_bytes: 42484}`, `permission_granted: true` (владельческая запись) и `ready_to_publish: true`. Если `storage` приходит как `null` или `available_bytes: 0`, аккаунту нужен `storage_deposit` на `social.near`, прежде чем новая запись сможет закрепиться. Если signer отличается от цели, ветка permission спрашивает `is_write_permission_granted({predecessor_id, key})` — тот же on-chain-ответ, который dapp видит, прежде чем писать от имени пользователя. Полную поверхность контракта см. в [SocialDB API](https://github.com/NearSocial/social-db#api). + +### Что `mob.near/widget/Profile` содержит прямо сейчас? + +SocialDB хранит BOS-виджеты как ключи `/widget/` на `social.near`. Один `keys` с типом возврата `BlockHeight` возвращает каталог плюс якоря последней записи по каждому виджету; один `get` возвращает точный исходник. + +```bash +ACCOUNT_ID=mob.near +WIDGET_NAME=Profile +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +KEYS_ARGS="$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + keys: [($account_id + "/widget/*")], + options: {return_type: "BlockHeight"} +}' | base64 | tr -d '\n')" + +curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$KEYS_ARGS" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"keys",args_base64:$args,finality:"final"} + }')" \ + | jq --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" ' + .result.result | implode | fromjson | .[$account_id].widget as $map + | { + total_widgets: ($map | length), + most_recently_written: ($map | to_entries | sort_by(-.value) | .[0:5] | map({widget: .key, last_write_block: .value})), + target_last_write_block: $map[$widget] + }' + +GET_ARGS="$(jq -nc --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" '{ + keys: [($account_id + "/widget/" + $widget)] +}' | base64 | tr -d '\n')" + +curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$GET_ARGS" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"get",args_base64:$args,finality:"final"} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" ' + .result.result | implode | fromjson | .[$account_id].widget[$widget] | split("\n")[0:20] | join("\n")' +``` + +Для `mob.near` каталог показывает 264 виджета; `Profile` последний раз записывался в блоке `86494825` — годами ранее, стабильно с тех пор — и исходник начинается с `const accountId = props.accountId ?? context.accountId;`. Тип возврата `BlockHeight` ничего не стоит дополнительно и превращает листинг ключей в дешёвую проверку актуальности. Сохраните блок последней записи, если позже захотите доказать, *какая транзакция* записала именно эту версию — передайте его в [Расширенный поиск записи SocialDB](https://docs.fastnear.com/ru/tx/socialdb-proofs). + +## Частые ошибки + +- Начинать в RPC, когда пользователю нужна сводка по активам или индексированная история. +- Забывать переключаться с обычного RPC на archival RPC для более старого state. +- Считать browser auth в UI документации продовым backend-паттерном. +- Оставаться в низкоуровневых вызовах статуса транзакции, когда вопрос уже стал forensic или историческим. + +## Связанные страницы + +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [Auth & Access](https://docs.fastnear.com/ru/auth) +- [FastNear API](https://docs.fastnear.com/ru/api) +- [Transactions API](https://docs.fastnear.com/ru/tx) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) + +--- + ## Снапшоты для валидаторов - HTML-маршрут: https://docs.fastnear.com/ru/snapshots @@ -1681,6 +2505,10 @@ sudo -v ; curl https://rclone.org/install.sh | sudo bash Требования к узлам смотрите в [nearcore](https://github.com/near/nearcore?tab=readme-ov-file#about-near), а исходники скриптов загрузки, которые используются в этих руководствах, — в [fastnear/static](https://github.com/fastnear/static). +## Нужен сценарий? + +Используйте [примеры снапшотов](https://docs.fastnear.com/ru/snapshots/examples) для практических примеров: выбора между оптимизированным `fast-rpc`, стандартным восстановлением RPC и архивными путями с разделением горячих и холодных данных. + ## Выберите сеть - [Снапшоты mainnet](https://docs.fastnear.com/ru/snapshots/mainnet) @@ -1688,6 +2516,72 @@ sudo -v ; curl https://rclone.org/install.sh | sudo bash --- +## Примеры snapshot + +- HTML-маршрут: https://docs.fastnear.com/ru/snapshots/examples +- Markdown-маршрут: https://docs.fastnear.com/ru/snapshots/examples.md + +**Источник:** [https://docs.fastnear.com/ru/snapshots/examples](https://docs.fastnear.com/ru/snapshots/examples) + +## Пути восстановления mainnet + +Выберите один класс — optimized `fast-rpc`, standard RPC или archival — и выполняйте только команды этого пути. Смешивание классов приводит к несогласованным данным узла. + +FastNear поддерживает эти скрипты ради скорости восстановления. Если в вашей среде требуется review изменений, скачайте скрипт и проверьте его перед запуском (вместо прямой передачи через pipe в `bash`). + +### Optimized mainnet `fast-rpc` + +```bash +DATA_PATH=~/.near/data + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone.sh \ + | DATA_PATH="$DATA_PATH" CHAIN_ID=mainnet RPC_TYPE=fast-rpc bash +``` + +### Standard mainnet RPC + +```bash +DATA_PATH=~/.near/data + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone.sh \ + | DATA_PATH="$DATA_PATH" CHAIN_ID=mainnet bash +``` + +### Archival mainnet + +Для archival нужны две загрузки из *одного и того же* среза снапшота. Зафиксируйте одно значение `LATEST` и переиспользуйте его и для hot-, и для cold-data — смешивание высот даёт внутренне несогласованный набор данных и удивляет nearcore на этапе настройки. + +```bash +HOT_DATA_PATH=~/.near/data +COLD_DATA_PATH=/mnt/hdds/cold-data + +LATEST="$(curl -s "https://snapshot.neardata.xyz/mainnet/archival/latest.txt")" +echo "Latest archival mainnet snapshot block: $LATEST" + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh \ + | DATA_TYPE=hot-data DATA_PATH="$HOT_DATA_PATH" CHAIN_ID=mainnet BLOCK="$LATEST" bash + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh \ + | DATA_TYPE=cold-data DATA_PATH="$COLD_DATA_PATH" CHAIN_ID=mainnet BLOCK="$LATEST" bash +``` + +## Частые ошибки + +- Использовать документацию по снапшотам, когда задача на самом деле про чтение данных цепочки. +- Выбирать archival-восстановление, когда достаточно standard или optimized RPC. +- Забывать про разделение hot/cold-хранилища для archival-данных. +- Переходить к командам до выбора сети и цели узла. + +## Связанные страницы + +- [Обзор snapshot](https://docs.fastnear.com/ru/snapshots) +- [Снапшоты mainnet](https://docs.fastnear.com/ru/snapshots/mainnet) +- [Снапшоты testnet](https://docs.fastnear.com/ru/snapshots/testnet) +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [NEAR Data API](https://docs.fastnear.com/ru/neardata) + +--- + ## mainnet - HTML-маршрут: https://docs.fastnear.com/ru/snapshots/mainnet @@ -1978,6 +2872,10 @@ https://transfers.main.fastnear.com - [Запрос переводов](https://docs.fastnear.com/ru/transfers/query) — лента по аккаунту с фильтрами по направлению, активу, сумме и времени +## Нужен сценарий? + +Используйте [Transfers API Examples](https://docs.fastnear.com/ru/transfers/examples) для практических примеров: узкие поиски переводов, пагинация через `resume_token` и переход к более широкому расследованию транзакций. + ## Устранение неполадок ### Нужны полные метаданные транзакции @@ -1990,6 +2888,117 @@ https://transfers.main.fastnear.com --- +## Примеры Transfers API + +- HTML-маршрут: https://docs.fastnear.com/ru/transfers/examples +- Markdown-маршрут: https://docs.fastnear.com/ru/transfers/examples.md + +**Источник:** [https://docs.fastnear.com/ru/transfers/examples](https://docs.fastnear.com/ru/transfers/examples) + +## Примеры + +Эти shell-примеры работают и на публичных Transfers и Transactions endpoint-ах. Если `FASTNEAR_API_KEY` уже задан в окружении, сниппеты автоматически пробросят его как bearer-заголовок. + +### Какая у этого аккаунта свежая активность по переводам? + +`/v0/transfers` всего с `account_id` и `desc: true` возвращает самые свежие переводы, касающиеся этого аккаунта, по всем типам активов, в обоих направлениях сразу. В каждой строке уже есть `human_amount`, `asset_id` и `transaction_id`, так что этот поток заодно служит быстрым сканом активности до того, как вы достанете фильтры. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id: $account_id, desc: true, limit: 5}')" \ + | jq '{ + recent: [.transfers[] | { + block_height, + asset_id, + human_amount, + other_account_id, + transfer_type, + tx: .transaction_id + }] + }' +``` + +Для `root.near` последние строки смешивают активы `FtTransfer` и `MtTransfer`. `asset_id` использует URI по NEP-стандартам (`native:near`, `nep141:...`, `nep245:...`), так что одно поле уже подсказывает, к какому стандарту тянуться дальше. Положительный `human_amount` означает, что аккаунт получил; отрицательный — что отправил. `other_account_id: null` — норма для multi-token-форм, где контрагент сидит внутри границы контракта, а не как отдельный аккаунт верхнего уровня. + +### Отфильтровать и листать ленту переводов одного аккаунта + +`/v0/transfers` возвращает отфильтрованную ленту плюс `resume_token`, который вы переиспользуете *без изменения фильтров*, чтобы продолжать листать. В каждой строке уже есть `human_amount`, `usd_amount`, `transaction_id` и `receipt_id` — большинство audit-вопросов закрываются без второго запроса. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +FEED="$(curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + account_id: $account_id, + direction: "receiver", + asset_id: "native:near", + min_amount: "1000000000000000000000000", + desc: true, + limit: 10 + }')")" + +echo "$FEED" | jq '{ + resume_token, + transfers: [.transfers[] | {block_height, amount, human_amount, usd_amount, other_account_id, transaction_id, receipt_id}] +}' +``` + +Для зафиксированного аккаунта это возвращает недавние входящие native-NEAR переводы не меньше 1 NEAR — в примерных строках видны native-переводы с `escrow.ai.near` и уже посчитанным USD. Чтобы получить следующую страницу, отправьте то же тело с верхнеуровневым `resume_token: ""`; изменение любого другого фильтра делает токен недействительным. + +Когда одной строке нужна точка исполнения, возьмите её `receipt_id` и сразу обратитесь к `/v0/receipt`: + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +FEED="$(curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + account_id: $account_id, + direction: "receiver", + asset_id: "native:near", + min_amount: "1000000000000000000000000", + desc: true, + limit: 10 + }')")" +RECEIPT_ID="$(echo "$FEED" | jq -r '.transfers[0].receipt_id')" + +curl -s "https://tx.main.fastnear.com/v0/receipt" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg receipt_id "$RECEIPT_ID" '{receipt_id: $receipt_id}')" \ + | jq '.receipt | {receipt_id, transaction_hash, receiver_id, predecessor_id, tx_block_height, is_success}' +``` + +Это тот же переход, что описан в [Превратить один receipt ID в читаемую историю транзакции](https://docs.fastnear.com/ru/tx/examples#receipt-id-to-readable-story) — один запрос возвращает и квитанцию, и её родительскую транзакцию целиком. + +## Частые ошибки + +- Использовать Transfers API, когда пользователю на самом деле нужны балансы, активы или сводки аккаунта. +- Считать историю переводов полной историей исполнения. +- Переиспользовать `resume_token` с другими фильтрами. + +## Связанные страницы + +- [Transfers API](https://docs.fastnear.com/ru/transfers) +- [Transactions API](https://docs.fastnear.com/ru/tx) +- [FastNear API](https://docs.fastnear.com/ru/api) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) + +--- + ## Транзакции API - HTML-маршрут: https://docs.fastnear.com/ru/tx @@ -2037,6 +3046,10 @@ https://tx.test.fastnear.com - [Поиск квитанции](https://docs.fastnear.com/ru/tx/receipt) — для расследования цепочки исполнения. - [Диапазон блоков](https://docs.fastnear.com/ru/tx/blocks) — когда нужен ограниченный по диапазону просмотр истории. +## Нужен сценарий? + +Используйте [примеры API транзакций](https://docs.fastnear.com/ru/tx/examples) для практических примеров: поиска транзакций, расследования квитанций, истории аккаунта и анализа диапазонов блоков. + ## Устранение неполадок ### Я ожидал, что здесь можно отправлять транзакции @@ -2053,6 +3066,551 @@ https://tx.test.fastnear.com --- +## Примеры Transactions + +- HTML-маршрут: https://docs.fastnear.com/ru/tx/examples +- Markdown-маршрут: https://docs.fastnear.com/ru/tx/examples.md + +**Источник:** [https://docs.fastnear.com/ru/tx/examples](https://docs.fastnear.com/ru/tx/examples) + +## Начните здесь + +Все shell-примеры ниже работают на публичных Transactions API-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### У меня один хеш транзакции. Что произошло? + +Вставьте хеш в `POST /v0/transactions` — один ответ обычно содержит всю историю. + +```bash +TX_HASH=7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq '{ + hash: .transactions[0].transaction.hash, + signer_id: .transactions[0].transaction.signer_id, + receiver_id: .transactions[0].transaction.receiver_id, + included_block_height: .transactions[0].execution_outcome.block_height, + actions: (.transactions[0].transaction.actions | map(if type == "string" then . else keys[0] end)), + first_receipt_id: .transactions[0].execution_outcome.outcome.status.SuccessReceiptId, + receipt_count: (.transactions[0].receipts | length) + }' +``` + +Для зафиксированного хеша `root.near` отправил один `Transfer` на `escrow.ai.near` в блоке `188976785`, с передачей в receipt `B8QzHQZ6VnUVy8zaVXCEkWuSs7MPb34yoHYixZV3Zdj1`. Если `receipt_count > 1` или следующий вопрос касается поведения на уровне receipt, переходите к [Какой receipt испустил этот лог или событие?](#какой-receipt-испустил-этот-лог-или-событие) или [`POST /v0/receipt`](https://docs.fastnear.com/ru/tx/receipt). + +### Какой receipt испустил этот лог или событие? + +Выведите список всех receipt транзакции с логами и флагом, содержат ли их логи ваш фрагмент. Совпадение доказывается, а не угадывается: у зафиксированной транзакции один receipt логирует `Transfer`, другой — `Refund`, и только сторона `Refund` переключается в `true`. + +```bash +TX_HASH=2KhhB1uDScGCFQfVchep7DiZTGTxMcgfUYHNzwf5e6uL +LOG_FRAGMENT=Refund +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg fragment "$LOG_FRAGMENT" ' + [ + .transactions[0].receipts[] + | select((.execution_outcome.outcome.logs | length) > 0) + | { + receipt_id: .receipt.receipt_id, + receiver_id: .receipt.receiver_id, + method_name: (.receipt.receipt.Action.actions[0] + | if type == "string" then . else (.FunctionCall.method_name // keys[0]) end), + matches_fragment: any(.execution_outcome.outcome.logs[]?; contains($fragment)), + logs: .execution_outcome.outcome.logs + } + ]' +``` + +Фрагмент `Refund` атрибутируется receipt `9sLHQpaGz3NnMNMn8zGrDUSyktR1q6ts2otr9mHkfD1w` на `wrap.near`, метод `ft_resolve_transfer`. Логи receipt живут на receipts, а не на транзакции, поэтому одного прохода достаточно — более глубокая async-трассировка не нужна. + +### Превратить один receipt ID в читаемую историю транзакции {#receipt-id-to-readable-story} + +`POST /v0/receipt` возвращает запись receipt **и** его полную родительскую транзакцию в одном ответе, поэтому единственного запроса хватает на всю историю — дополнительный `/v0/transactions` не нужен. + +```bash +RECEIPT_ID=B8QzHQZ6VnUVy8zaVXCEkWuSs7MPb34yoHYixZV3Zdj1 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/receipt" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg receipt_id "$RECEIPT_ID" '{receipt_id: $receipt_id}')" \ + | jq '{ + receipt: { + receipt_id: .receipt.receipt_id, + type: .receipt.receipt_type, + is_success: .receipt.is_success, + receipt_block: .receipt.block_height, + tx_block: .receipt.tx_block_height, + predecessor_id: .receipt.predecessor_id, + receiver_id: .receipt.receiver_id, + transaction_hash: .receipt.transaction_hash + }, + parent_transaction: { + signer_id: .transaction.transaction.signer_id, + receiver_id: .transaction.transaction.receiver_id, + action_types: (.transaction.transaction.actions | map(if type == "string" then . else keys[0] end)) + } + }' +``` + +Для зафиксированного receipt это возвращает `Action`-receipt от `root.near` к `escrow.ai.near`, который успешно выполнился в блоке `188976786`, через один блок после попадания родительской транзакции `7ZKnhzt2…`, — один `Transfer` (3.5 NEAR, в сыром `.transaction.transaction.actions` видимо как `3500000000000000000000000` yocto). Если интересным якорем становится родительская транзакция, хеш у вас уже есть — переиспользуйте его в [У меня один хеш транзакции. Что произошло?](#у-меня-один-хеш-транзакции-что-произошло). + +## Сбои и async + +### Доказать, что один провалившийся action откатил весь batch + +Один batch отправил `CreateAccount → Transfer → AddKey → FunctionCall`, и финальный вызов попал в отсутствующий метод. Индексированная запись транзакции уже несёт упорядоченный batch *и* точный сбой на уровне receipt, поэтому одного запроса хватает, чтобы ответить «что пытались и что сломалось»; проверка через `view_account` затем доказывает, что предыдущие actions откатились. + +```bash +TX_HASH=CrhH3xLzbNwNMGgZkgptXorwh8YmqxRGuA6Mc11MkU6M +NEW_ACCOUNT_ID=rollback-mo4vmkig.temp.mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.test.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq '{ + action_types: (.transactions[0].transaction.actions | map(if type == "string" then . else keys[0] end)), + final_method: .transactions[0].transaction.actions[3].FunctionCall.method_name, + tx_handoff: .transactions[0].execution_outcome.outcome.status, + receipt_failure: ( + first( + .transactions[0].receipts[] + | select(.execution_outcome.outcome.status.Failure != null) + | .execution_outcome.outcome.status.Failure.ActionError + ) + ) + }' +``` + +Статус на уровне транзакции — `SuccessReceiptId`: транзакция успешно передала свои batched actions в receipt. Сбой лежит слоем ниже на этом receipt: `index: 3` (именно `FunctionCall`), вид `CodeDoesNotExist` на `rollback-mo4vmkig.temp.mike.testnet`. `SuccessReceiptId` в tx-outcome означает «handoff прошёл», а не «всё завершилось» — реальная ловушка, если смотреть только на статус уровня транзакции. + +Теперь докажите откат предыдущих actions: спросите аккаунт, который batch *пытался* создать: + +```bash +NEW_ACCOUNT_ID=rollback-mo4vmkig.temp.mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.testnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$NEW_ACCOUNT_ID" '{ + jsonrpc: "2.0", id: "fastnear", method: "query", + params: {request_type: "view_account", account_id: $account_id, finality: "final"} + }')" \ + | jq '{error: .error.cause.name, requested_account_id: .error.cause.info.requested_account_id}' +``` + +`UNKNOWN_ACCOUNT` — это и есть доказательство. Если бы `CreateAccount` закрепился, `view_account` вернул бы результат; раз нет — предыдущие `Transfer` и `AddKey` из того же batched-receipt тоже не закрепились. + +### Когда транзакция выглядит успешной — что на самом деле произошло? + +Внешний `execution_outcome.outcome.status` рапортует `SuccessReceiptId`, как только сработал handoff первого receipt, — и ничего не говорит о том, успешны ли дочерние receipts и отработал ли callback на исходном контракте. Один pipeline над `/v0/transactions` отвечает сразу на все три вопроса. + +```bash +TX_HASH=2KhhB1uDScGCFQfVchep7DiZTGTxMcgfUYHNzwf5e6uL +ORIGIN_CONTRACT_ID=wrap.near +CALLBACK_METHOD=ft_resolve_transfer +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg origin "$ORIGIN_CONTRACT_ID" --arg callback "$CALLBACK_METHOD" '{ + outer: { + method: .transactions[0].transaction.actions[0].FunctionCall.method_name, + tx_handoff: (.transactions[0].execution_outcome.outcome.status | keys[0]) + }, + callback: { + expected_on: $origin, + method: $callback, + ran: any( + .transactions[0].receipts[]; + .receipt.receiver_id == $origin + and (.receipt.receipt.Action.actions[0].FunctionCall.method_name // "") == $callback + ) + }, + descendant_failures: [ + .transactions[0].receipts[] + | select(.execution_outcome.outcome.status.Failure != null) + | { + receiver_id: .receipt.receiver_id, + method: (.receipt.receipt.Action.actions[0].FunctionCall.method_name // "system"), + cause: .execution_outcome.outcome.status.Failure + } + ] + }' +``` + +Для зафиксированной транзакции `outer.method` — `ft_transfer_call`, а `outer.tx_handoff` — `SuccessReceiptId`: транзакция чисто запустила свой первый receipt, и если смотреть только сюда, можно назвать это победой. `descendant_failures` рассказывают вторую историю: `ft_on_transfer` на `v2.ref-finance.near` упал с `E51: contract paused` — DEX был на паузе во время этого свопа и не мог принять wrapped NEAR. `callback.ran: true` — третью: callback `ft_resolve_transfer` на `wrap.near` всё равно отработал. Сбой ниже по цепочке никогда не мешает callback исходного контракта — именно так NEP-141 возвращает отправителю средства, когда получатель их отклонил. + +Успех receipt не транзитивен. Протокол может чисто отдать handoff и при этом увидеть, как отцеплённая работа провалится позже; callback исходного контракта отработает в любом случае. Прочитайте эти три поля вместе — и async-история становится читаемой без ручного обхода цепочки receipts. Чтобы вытянуть сам лог `Refund`, переходите к [Какой receipt испустил этот лог или событие?](#какой-receipt-испустил-этот-лог-или-событие). + +### Сопоставить запрос OutLayer с его TEE-разрешением + +[OutLayer](https://outlayer.fastnear.com) разделяет один логический вызов на две транзакции: пользователь подписывает `request_execution` на `outlayer.near`, worker в Intel TDX запускает нужный WASM off-chain, затем `worker.outlayer.near` присылает результат через `submit_execution_output_and_resolve`. Обе половины несут один и тот же `request_id` — передайте оба tx-хеша в один запрос `/v0/transactions` и извлеките это поле с каждой стороны, чтобы подтвердить пару. + +```bash +REQUEST_TX=BZDQAxEdpQ9wUGXmXTa2APwFLDTTqTy5ucrBPsfgZeyz +WORKER_TX=3NYD4Mkn5cwkuVkGP9PPoiJ9PB5Vr7v6r8CwSswtHVA3 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg a "$REQUEST_TX" --arg b "$WORKER_TX" '{tx_hashes: [$a, $b]}')" \ + | jq '[ + .transactions[] + | { + role: (if .transaction.actions[0].FunctionCall.method_name == "request_execution" + then "request" else "worker" end), + hash: .transaction.hash, + signer: .transaction.signer_id, + method: .transaction.actions[0].FunctionCall.method_name, + block: .execution_outcome.block_height, + request_id: ( + if .transaction.actions[0].FunctionCall.method_name == "request_execution" + then (.receipts[0].execution_outcome.outcome.logs[] | select(startswith("EVENT_JSON")) + | sub("EVENT_JSON:"; "") | fromjson | .data[0].request_data | fromjson | .request_id) + else (.receipts[0].receipt.receipt.Action.actions[0].FunctionCall.args + | @base64d | fromjson | .request_id) + end + ) + } + ]' +``` + +Обе строки несут `request_id: 1868`, подтверждая пару. Половина-запрос, подписанная `retrorn.near` в блоке `194832281`, лежит в логе `EVENT_JSON:` её receipt (это yield/resume-паттерн NEAR — on-chain-обещание приостанавливается, пока TDX-worker выполняется). Половина-worker приходит через 11 блоков с `submit_execution_output_and_resolve`, подписанной `worker.outlayer.near`, и её `request_id` достаётся прямо из base64-обёрнутых `FunctionCall.args`. Те же два payload несут и более богатый отпечаток — `sender_id`, `project_id`, `code_hash`, `resources_used.instructions`, `resources_used.time_ms`, размер зашифрованного результата в байтах — если нужно проверить, что именно исполнилось; этот минимальный pipeline лишь подтверждает, что половины принадлежат друг другу. `/v0/transactions` отдаёт исторические пары бессрочно, поэтому archival RPC для самой трассировки не нужен даже через недели. + +## Частые ошибки + +- Пытаться отправить транзакцию через history-API вместо raw RPC. +- Использовать Transactions API, когда пользователю нужны только текущие балансы или активы. +- Спускаться в raw RPC до того, как индексированная история ответила на читаемый вопрос «что произошло?». + +## Связанные страницы + +- [Transactions API](https://docs.fastnear.com/ru/tx) +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [FastNear API](https://docs.fastnear.com/ru/api) +- [NEAR Data API](https://docs.fastnear.com/ru/neardata) +- [Berry Club: живая доска и один путь исторической реконструкции](https://docs.fastnear.com/ru/tx/examples/berry-club) +- [Расширенный поиск записи SocialDB](https://docs.fastnear.com/ru/tx/socialdb-proofs) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) + +--- + +## Berry Club: как читать живую доску и разбирать одну эпоху + +- HTML-маршрут: https://docs.fastnear.com/ru/tx/examples/berry-club +- Markdown-маршрут: https://docs.fastnear.com/ru/tx/examples/berry-club.md + +**Источник:** [https://docs.fastnear.com/ru/tx/examples/berry-club](https://docs.fastnear.com/ru/tx/examples/berry-club) + +{/* FASTNEAR_AI_DISCOVERY: Этот walkthrough показывает краткий и полезный путь для Berry Club: сначала прочитайте живую доску через RPC get_lines, а Transactions API используйте только тогда, когда нужно восстановить одну более раннюю эпоху по draw-вызовам. */} + +# Berry Club: как читать живую доску и разбирать одну эпоху + +Используйте этот walkthrough, когда живую доску читать легко, но нужен один понятный путь к исторической реконструкции. + +Начните с живой доски. Если этого уже достаточно для ответа, на этом можно остановиться. + +Переходите к Transactions API только тогда, когда вопрос становится историческим: «как Berry Club выглядел в одной более ранней эпохе и какие `draw`-вызовы сделали доску именно такой?» + +Эти shell-примеры работают и с публичными RPC и Transactions endpoint-ами. Если `FASTNEAR_API_KEY` уже задан в окружении, FastNear-вызовы автоматически пробросят его как bearer-заголовок. + +Карточка живой доски: запрашивает `berryclub.ek.near` `get_lines` через mainnet RPC и рендерит текущую сетку 50x50 в интерфейсе документации. + +## 1. Прочитайте живую доску + +Это самый короткий полезный запрос: + +```bash +ARGS_BASE64="$(jq -nc '{lines: [range(0;50)]}' | base64 | tr -d '\n')" +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "{ + \"jsonrpc\": \"2.0\", + \"id\": \"berry-live-board\", + \"method\": \"query\", + \"params\": { + \"request_type\": \"call_function\", + \"finality\": \"final\", + \"account_id\": \"berryclub.ek.near\", + \"method_name\": \"get_lines\", + \"args_base64\": \"$ARGS_BASE64\" + } + }" | jq '.result | {block_height, line_count: (.result | implode | fromjson | length)}' +``` + +Этот запрос отдаёт текущую доску 50x50 прямо из контракта. Дальше нужно только декодировать каждую base64-строку в 50 цветов пикселей. + +## 2. Восстановите одну более раннюю эпоху + +Когда нужна история, держите путь коротким: + +1. ограничьте одну эпоху +2. получите кандидатные `draw`-транзакции для `berryclub.ek.near` +3. раскройте эти хеши +4. проиграйте массивы `pixels` от старых к новым + +В этом примере используется узкое окно вокруг блока `97601515`: + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://tx.main.fastnear.com/v0/account \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{ + "account_id": "berryclub.ek.near", + "is_function_call": true, + "is_receiver": true, + "is_real_receiver": true, + "from_tx_block_height": 97576515, + "to_tx_block_height": 97601516, + "desc": false, + "limit": 200 + }' | jq '.account_txs | map({transaction_hash, tx_block_height}) | .[-5:]' +``` + +Если окно ещё нужно подобрать, сначала можно использовать [`/v0/blocks`](https://docs.fastnear.com/ru/tx/blocks). Это не часть основного Berry Club-сценария. + +Раскройте кандидатные хеши и оставьте только верхнеуровневые вызовы `draw`: + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://tx.main.fastnear.com/v0/transactions \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{ + "tx_hashes": [ + "Hq5qwsuiM2emJrqczWM9awCa7o6sTBYqYpcifUX2SUhQ", + "8tBip5M2TrozhSyepAA3tYXpyKooi5t7b9c64wXjFvfL" + ] + }' | jq '.transactions[] + | select(.transaction.receiver_id == "berryclub.ek.near") + | .transaction.actions[]?.FunctionCall + | select(.method_name == "draw") + | {method_name, args: (.args | @base64d | fromjson)}' +``` + +Затем проиграйте массивы `pixels` от старых к новым: + +```javascript +const board = Array.from({ length: 50 }, () => Array(50).fill(0)); + +for (const drawTx of drawTransactionsOldestFirst) { + for (const pixel of drawTx.args.pixels) { + if (pixel.x < 0 || pixel.x >= 50 || pixel.y < 0 || pixel.y >= 50) { + continue; + } + + board[pixel.y][pixel.x] = pixel.color; + } +} +``` + +В этом и состоит исторический паттерн. У Berry Club нет готового эндпоинта «доска на блоке N», поэтому старые эпохи восстанавливаются проигрыванием `draw`-записей. + +## Связанные руководства + +- [RPC: call_function](https://docs.fastnear.com/ru/rpc/contract/call-function) +- [Transactions API: история аккаунта](https://docs.fastnear.com/ru/tx/account) +- [Transactions API: транзакции по хешу](https://docs.fastnear.com/ru/tx/transactions) + +--- + +## Расширенный поиск записи SocialDB + +- HTML-маршрут: https://docs.fastnear.com/ru/tx/socialdb-proofs +- Markdown-маршрут: https://docs.fastnear.com/ru/tx/socialdb-proofs.md + +**Источник:** [https://docs.fastnear.com/ru/tx/socialdb-proofs](https://docs.fastnear.com/ru/tx/socialdb-proofs) + +# Расширенный поиск записи SocialDB + +Используйте эту страницу только тогда, когда отправная точка — уже читаемое значение SocialDB из `api.near.social`, а следующий вопрос относится к историческому поиску записи. + +Эти shell-шаги работают и с публичными endpoint-ами SocialDB и FastNear. Если `FASTNEAR_API_KEY` уже задан в окружении, FastNear-вызовы автоматически пробросят его как bearer-заголовок. + +Для FastNear-first-задач сначала откройте [Transactions Examples](https://docs.fastnear.com/ru/tx/examples). Сюда переходите только тогда, когда вопрос звучит как «какая запись сделала это читаемое значение SocialDB истинным?». + +## Канонический пример: доказать, что `root.near` установил `profile.name` в `Illia` + +Используйте этот сценарий, когда читаемый факт уже звучит как «текущее `profile.name` равно `Illia`», а остаётся вопрос, какая запись сделала это поле истинным. + +Это единственный нюанс SocialDB, который стоит запомнить: для исторического доказательства правильным мостом обычно служит `:block` на уровне поля, а не `:block` родительского объекта. + +Для этого живого якоря: + +- текущее `profile.name`: `Illia` +- блок записи SocialDB на уровне поля: `75590392` +- receipt ID: `GYvnvBxWA46UGa3aGEkqUBeT7hxhVXk2iZScJFZWU8Se` +- хеш исходной транзакции: `7HtFWv51k5Bispmh1WYPbAVkxr2X4AL6n98DhcQwVw7w` +- внешний блок транзакции: `75590391` + +### Shell-сценарий + +1. Прочитайте поле из NEAR Social и сохраните блок записи на уровне поля. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name + +PROFILE="$(curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')")" + +echo "$PROFILE" | jq --arg account_id "$ACCOUNT_ID" '{ + current_name: .[$account_id].profile.name[""], + field_block_height: .[$account_id].profile.name[":block"], + parent_profile_block_height: .[$account_id].profile[":block"] +}' + +PROFILE_BLOCK_HEIGHT="$(echo "$PROFILE" | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]')" +``` + +2. Переиспользуйте этот блок уровня поля в FastNear block receipts и восстановите receipt вместе с tx hash. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +PROFILE_BLOCK_HEIGHT="$( + curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]' +)" +BLOCK_RECEIPTS="$(curl -s "https://tx.main.fastnear.com/v0/block" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --argjson block_id "$PROFILE_BLOCK_HEIGHT" '{ + block_id: $block_id, + with_transactions: false, + with_receipts: true + }')")" + +echo "$BLOCK_RECEIPTS" | jq --arg account_id "$ACCOUNT_ID" '{ + profile_receipt: ( + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | {receipt_id, transaction_hash, block_height, tx_block_height} + ) + ) +}' + +PROFILE_TX_HASH="$(echo "$BLOCK_RECEIPTS" | jq -r --arg account_id "$ACCOUNT_ID" ' + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | .transaction_hash + )')" +``` + +3. Переиспользуйте этот tx hash в `POST /v0/transactions` и декодируйте payload записи SocialDB. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +PROFILE_BLOCK_HEIGHT="$( + curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]' +)" +PROFILE_TX_HASH="$( + curl -s "https://tx.main.fastnear.com/v0/block" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --argjson block_id "$PROFILE_BLOCK_HEIGHT" '{ + block_id: $block_id, + with_transactions: false, + with_receipts: true + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" ' + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | .transaction_hash + )' +)" +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$PROFILE_TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg account_id "$ACCOUNT_ID" '{ + transaction: { + hash: .transactions[0].transaction.hash, + signer_id: .transactions[0].transaction.signer_id, + receiver_id: .transactions[0].transaction.receiver_id, + included_block_height: .transactions[0].execution_outcome.block_height + }, + write_proof: ( + .transactions[0].receipts[0].receipt.receipt.Action.actions[0].FunctionCall + | (.args | @base64d | fromjson | .data[$account_id].profile) as $profile + | { + method_name, + profile_name: $profile.name, + image_fields: (($profile.image // {}) | keys), + linktree_keys: (($profile.linktree // {}) | keys) + } + ) + }' +``` + +Это и есть весь паттерн lookup: читаемое значение, блок уровня поля, мост через receipt и payload транзакции. + +Тот же мост работает и для других читаемых значений SocialDB: + +- вариант для связи подписки: `root.near -> mob.near`, блок `79152039`, tx `DvNoqtDrruhmcq7mPpxdFacph2ZCqSzMFF5ZqMRFG78q` +- вариант для исходника виджета: `root.near/widget/Profile`, блок `76029540`, tx `ELS3DrE4Upoc91ZnBh4thVugxCUBAbaLFB4nyKsoyRNP` + +Ключевая идея не меняется: начните с читаемого значения и его write-block, восстановите receipt `*.near -> social.near` из блока, а затем декодируйте payload `social.near set` из исходной транзакции. + +--- + ## RPC протокола NEAR: Просмотр ключа доступа - HTML-маршрут: https://docs.fastnear.com/ru/rpcs/account/view_access_key @@ -31801,3 +33359,10 @@ https://tx.test.fastnear.com "refName": "TransfersResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/llms.txt b/static/ru/llms.txt index 985f6d7..bc222fb 100644 --- a/static/ru/llms.txt +++ b/static/ru/llms.txt @@ -16,8 +16,10 @@ AI-читабельные индексы для гайдов FastNear, RPC-сп - [Справочник API](https://docs.fastnear.com/ru/api/reference.md): Руководство по маршрутизации между семействами FastNear REST API и их отличия от прямых методов JSON-RPC. - [Аутентификация и доступ](https://docs.fastnear.com/ru/auth.md): Один API-ключ FastNear работает и для RPC, и для REST API — отправляйте его через заголовок Authorization Bearer или как URL-параметр. - [KV FastData API](https://docs.fastnear.com/ru/fastdata/kv.md): Запросы только для чтения «ключ–значение» поверх FastData для сценариев с `predecessor_id`, аккаунтом, ключом и пакетным чтением. -- [NEAR Data API](https://docs.fastnear.com/ru/neardata.md): Кэшированные и архивные чтения по блокам для оптимистичных, финализированных и сценариев с перенаправлением. +- [Примеры KV FastData](https://docs.fastnear.com/ru/fastdata/kv/examples.md): Практические примеры KV FastData: точные ключи, scoped-записи, история ключа и переход к точному состоянию. +- [NEAR Data API](https://docs.fastnear.com/ru/neardata.md): Недавние чтения по блокам и шардам для мониторинга активности контракта, подтверждения оптимистичных наблюдений и проверки изменений на уровне шарда. - [Справочник RPC](https://docs.fastnear.com/ru/rpc.md): Прямой доступ по JSON-RPC к узлам NEAR от FastNear для запросов состояния, блоков, вызовов контрактов и отправки транзакций. +- [Примеры RPC](https://docs.fastnear.com/ru/rpc/examples.md): Практические примеры RPC: проверки состояния, инспекция блоков, чтение контрактов и отправка транзакций. - [API переводов](https://docs.fastnear.com/ru/transfers.md): История переводов NEAR и FT-токенов по аккаунтам для продуктовых лент и инструментов расследования. - [Транзакции API](https://docs.fastnear.com/ru/tx.md): Индексированные запросы по транзакциям, квитанциям, истории аккаунтов и истории блоков для FastNear. @@ -30,12 +32,19 @@ AI-читабельные индексы для гайдов FastNear, RPC-сп ## Другие гайды +- [Примеры API](https://docs.fastnear.com/ru/api/examples.md): Практические примеры FastNear API: поиск аккаунта по ключу, просмотр активов и классификация стейкинга. - [Руководство по интернационализации](https://docs.fastnear.com/ru/internationalization.md): Руководство для сопровождающих по добавлению локалей Docusaurus, локализованных оверлеев FastNear и безопасного для discovery процесса перевода. +- [Примеры NEAR Data](https://docs.fastnear.com/ru/neardata/examples.md): Практические примеры NEAR Data: живой мониторинг, optimistic-проверки и доказательство на уровне shard. - [redocly-config](https://docs.fastnear.com/ru/redocly-config.md): Исторические заметки о прежнем бэкенде Redocly и о том, где он всё ещё важен для проверки документации FastNear. +- [Примеры Transfers API](https://docs.fastnear.com/ru/transfers/examples.md): Практические примеры: фильтрация ленты переводов, пагинация и переход к истории транзакций. +- [Примеры Transactions](https://docs.fastnear.com/ru/tx/examples.md): Практические расследования транзакций: хеши, receipts, async-сбои и callback. +- [Berry Club: как читать живую доску и разбирать одну эпоху](https://docs.fastnear.com/ru/tx/examples/berry-club.md): Прочитайте живую доску Berry Club через RPC get_lines, а затем используйте Transactions API, чтобы восстановить одну более раннюю эпоху. +- [Расширенный поиск записи SocialDB](https://docs.fastnear.com/ru/tx/socialdb-proofs.md): Один короткий расширенный сценарий, который начинается с читаемого значения SocialDB и восстанавливает транзакцию записи за ним. ## Снапшоты - [Снапшоты для валидаторов](https://docs.fastnear.com/ru/snapshots.md): Пути загрузки снапшотов FastNear для подъёма и восстановления узлов NEAR. +- [Примеры snapshot](https://docs.fastnear.com/ru/snapshots/examples.md): Практические примеры восстановления узла: optimized, standard и archival. - [mainnet](https://docs.fastnear.com/ru/snapshots/mainnet.md): Скачайте RPC- и архивные снапшоты mainnet для быстрого развёртывания NEAR-инфраструктуры на базе FastNear. - [testnet](https://docs.fastnear.com/ru/snapshots/testnet.md): Скачайте RPC- и архивные снапшоты testnet для быстрого развёртывания NEAR-инфраструктуры на базе FastNear. diff --git a/static/ru/neardata.md b/static/ru/neardata.md index 8e11085..29a87d5 100644 --- a/static/ru/neardata.md +++ b/static/ru/neardata.md @@ -2,7 +2,7 @@ # NEAR Data API -NEAR Data API — это поверхность для чтения данных почти в реальном времени, а также по семействам блоков. Используйте её, когда нужны свежие срезы блоков, вспомогательные маршруты с перенаправлением или недавние финализированные и оптимистичные чтения, но без позиционирования продукта как потокового сервиса. +NEAR Data API — это поверхность для недавних блоков и шардов. Используйте её, когда нужны свежие срезы блоков, мониторинг активности контракта, вспомогательные маршруты с перенаправлением или сравнение оптимистичных и финализированных чтений без превращения продукта в потоковый API. ## Базовые URL @@ -17,8 +17,9 @@ https://testnet.neardata.xyz ## Лучше всего подходит для - опроса недавних финализированных и оптимистичных блоков; -- вспомогательных маршрутов по блокам и сценариев с перенаправлением; -- лёгких проверок свежести данных и мониторинга. +- обнаружения того, появился ли живой контракт в недавнем блоке и изменил ли он состояние; +- сравнения оптимистичного сигнала с финализированным подтверждением; +- проверки одного недавнего шарда, когда уже известно, какой блок важен. ## Когда его не стоит использовать @@ -33,9 +34,14 @@ https://testnet.neardata.xyz ## С чего обычно начинают -- [Оптимистичный блок](https://docs.fastnear.com/ru/neardata/block-optimistic) — для самого свежего опроса блоков. -- [Финализированный блок по высоте](https://docs.fastnear.com/ru/neardata/block) и [Заголовки блока](https://docs.fastnear.com/ru/neardata/block-headers) — для запросов по финализированным блокам. -- [Перенаправление на последний финализированный блок](https://docs.fastnear.com/ru/neardata/last-block-final) и [Перенаправление на последний оптимистичный блок](https://docs.fastnear.com/ru/neardata/last-block-optimistic) — когда нужны вспомогательные маршруты с перенаправлением. +- [Перенаправление на последний финализированный блок](https://docs.fastnear.com/ru/neardata/last-block-final) и [Перенаправление на последний оптимистичный блок](https://docs.fastnear.com/ru/neardata/last-block-optimistic) — когда нужно быстро узнать самый новый недавний блок. +- [Финализированный блок по высоте](https://docs.fastnear.com/ru/neardata/block) — когда нужен один недавний гидратированный блок с уже приложенными данными по шардам. +- [Шард блока](https://docs.fastnear.com/ru/neardata/block-shard) — когда недавний блок уже показал нужный шард и его надо разобрать глубже. +- [Заголовки блока](https://docs.fastnear.com/ru/neardata/block-headers) — когда важнее движение головы цепочки и финальности, а не широкий блоковый документ. + +## Нужен сценарий? + +Используйте [примеры NEAR Data API](https://docs.fastnear.com/ru/neardata/examples) для практических примеров: обнаружения активности контракта, сравнения оптимистичных и финализированных наблюдений, а также проверки изменений на уровне шарда. ## Устранение неполадок @@ -50,3 +56,10 @@ https://testnet.neardata.xyz ### Нужна потоковая передача, а не опрос Эта поверхность предназначена для чтения через опрос почти в реальном времени. Не позиционируйте её как продукт на основе WebSocket или вебхуков. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/block-chunk.md b/static/ru/neardata/block-chunk.md index e882ae5..e4e55f7 100644 --- a/static/ru/neardata/block-chunk.md +++ b/static/ru/neardata/block-chunk.md @@ -906,3 +906,10 @@ "refName": "ChunkDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/block-chunk/index.md b/static/ru/neardata/block-chunk/index.md index e882ae5..e4e55f7 100644 --- a/static/ru/neardata/block-chunk/index.md +++ b/static/ru/neardata/block-chunk/index.md @@ -906,3 +906,10 @@ "refName": "ChunkDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/block-headers.md b/static/ru/neardata/block-headers.md index 48e7aba..bf2fdb0 100644 --- a/static/ru/neardata/block-headers.md +++ b/static/ru/neardata/block-headers.md @@ -251,3 +251,10 @@ "refName": "BlockEnvelope" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/block-headers/index.md b/static/ru/neardata/block-headers/index.md index 48e7aba..bf2fdb0 100644 --- a/static/ru/neardata/block-headers/index.md +++ b/static/ru/neardata/block-headers/index.md @@ -251,3 +251,10 @@ "refName": "BlockEnvelope" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/block-optimistic.md b/static/ru/neardata/block-optimistic.md index 1930041..e264df9 100644 --- a/static/ru/neardata/block-optimistic.md +++ b/static/ru/neardata/block-optimistic.md @@ -1851,3 +1851,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/block-optimistic/index.md b/static/ru/neardata/block-optimistic/index.md index 1930041..e264df9 100644 --- a/static/ru/neardata/block-optimistic/index.md +++ b/static/ru/neardata/block-optimistic/index.md @@ -1851,3 +1851,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/block-shard.md b/static/ru/neardata/block-shard.md index 9610aec..35b2376 100644 --- a/static/ru/neardata/block-shard.md +++ b/static/ru/neardata/block-shard.md @@ -1630,3 +1630,10 @@ "refName": "ShardDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/block-shard/index.md b/static/ru/neardata/block-shard/index.md index 9610aec..35b2376 100644 --- a/static/ru/neardata/block-shard/index.md +++ b/static/ru/neardata/block-shard/index.md @@ -1630,3 +1630,10 @@ "refName": "ShardDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/block.md b/static/ru/neardata/block.md index 8cdba8d..9a05b02 100644 --- a/static/ru/neardata/block.md +++ b/static/ru/neardata/block.md @@ -1851,3 +1851,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/block/index.md b/static/ru/neardata/block/index.md index 8cdba8d..9a05b02 100644 --- a/static/ru/neardata/block/index.md +++ b/static/ru/neardata/block/index.md @@ -1851,3 +1851,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/examples.md b/static/ru/neardata/examples.md new file mode 100644 index 0000000..3639e91 --- /dev/null +++ b/static/ru/neardata/examples.md @@ -0,0 +1,147 @@ +**Источник:** [https://docs.fastnear.com/ru/neardata/examples](https://docs.fastnear.com/ru/neardata/examples) + +## Примеры + +NEAR Data возвращает каждый блок полностью гидратированным одним JSON-документом — header плюс per-shard chunks, receipts, результаты исполнения и state changes, — так что один `curl` уже даёт всё необходимое, чтобы отфильтровать нужный контракт без второго запроса. + +Все shell-примеры ниже работают на публичных NEAR Data-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### На каком блоке NEAR сейчас? + +`/v0/last_block/final` отдаёт 302-редирект на текущий финализированный блок. Прежде чем фильтровать по конкретному контракту, полезно увидеть, как выглядит один блок на уровне протокола: транзакции приходят с разбивкой по shard, поэтому общее число транзакций в блоке — это сумма по shards, а не одно поле верхнего уровня. + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + height: .block.header.height, + timestamp_nanosec: .block.header.timestamp_nanosec, + txs_per_shard: [.shards[] | {shard_id, tx_count: (.chunk.transactions | length)}], + total_txs: ([.shards[].chunk.transactions[]?] | length) + }' +``` + +Живой блок показывает 9 shards и горсть транзакций, распределённых по ним — большинство shards в любом блоке пустые, а активность концентрируется на тех shards, где живут загруженные контракты. `timestamp_nanosec` — это Unix-время в наносекундах (делите на 1e9, чтобы получить секунды). С этим одним вызовом у вас уже есть всё необходимое для дальнейшего копания — примеры фильтрации ниже просто применяют jq к тому же ответу. + +### Был ли мой контракт затронут в последнем финализированном блоке? + +`/v0/last_block/final` отдаёт 302-редирект на текущий финализированный блок. Контракт может проявиться либо в `transactions` chunk (когда он `receiver_id`), либо в `receipts` (когда прилетает cross-shard-вызов), поэтому один проход jq по shards покрывает оба случая. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" \ + | jq --arg contract "$TARGET_CONTRACT" '{ + height: .block.header.height, + contract: $contract, + touched_shards: [ + .shards[] | { + shard_id, + txs: [.chunk.transactions[]? | select(.transaction.receiver_id == $contract) | .transaction.hash], + receipts: [.chunk.receipts[]? | select(.receiver_id == $contract) | .receipt_id] + } | select((.txs | length) + (.receipts | length) > 0) + ] + }' +``` + +`touched_shards: []` — полный ответ для тихого блока. Непустой список называет shards, где контракт появился, и отдаёт конкретные `tx`-хеши или `receipt_id` — передавайте хеш в [Transactions API](https://docs.fastnear.com/ru/tx), когда нужна человекочитаемая история. Receipts без парных `txs` — это нормально: cross-contract-вызов приходит как incoming receipt в этом блоке, даже если исходная транзакция была раньше. + +### Увидел ли я активность в optimistic-режиме, и догнала ли её finality? + +Optimistic-блоки ходят по `/v0/block_opt/{height}` примерно на секунду впереди `/v0/block/{height}`. Цикл мониторинга может действовать по optimistic-сигналу и ожидать, что тот же ответ придёт на финализированный эндпоинт через один блок — если только стресс сети не расширит разрыв, и тогда финализированный fetch вернёт `null`, а вы подождёте. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +count_touches() { + jq --arg contract "$1" ' + [.shards[] + | ([.chunk.transactions[]? | select(.transaction.receiver_id == $contract)] | length) + + ([.chunk.receipts[]? | select(.receiver_id == $contract)] | length)] + | add // 0' +} + +OPT_LOCATION="$( + curl -s -D - -o /dev/null "${AUTH_HEADER[@]}" "https://mainnet.neardata.xyz/v0/last_block/optimistic" \ + | awk 'tolower($1) == "location:" {print $2}' | tr -d '\r' +)" +OPT_HEIGHT="${OPT_LOCATION##*/}" + +echo "optimistic @ $OPT_HEIGHT: $(curl -s "https://mainnet.neardata.xyz$OPT_LOCATION" \ + "${AUTH_HEADER[@]}" | count_touches "$TARGET_CONTRACT") touches" +FINAL="$(curl -s "https://mainnet.neardata.xyz/v0/block/$OPT_HEIGHT" \ + "${AUTH_HEADER[@]}")" +if [ "$(printf '%s' "$FINAL" | jq 'type')" = '"null"' ]; then + echo "finalized @ $OPT_HEIGHT: not caught up yet" +else + echo "finalized @ $OPT_HEIGHT: $(printf '%s' "$FINAL" | count_touches "$TARGET_CONTRACT") touches" +fi +``` + +На здоровом mainnet оба счётчика совпадают в пределах секунды. Ценность — в самом шаблоне: optimistic-поток даёт ответ, на который можно реагировать сразу, а финализированный приходит через блок как надёжное подтверждение. + +### Какой shard действительно изменил состояние моего контракта? + +В большинстве финализированных блоков нет мутации состояния ни для одного конкретного контракта — активность разрежена и привязана к shard. Идите назад от финализированной головы, пока состояние контракта реально не изменится, и откройте этот shard для payload мутации. Вызов уровня блока говорит, *на каком* shard это случилось; вызов уровня shard — *как*. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +HEAD="$(curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" | jq '.block.header.height')" +FOUND_HEIGHT="" +FOUND_SHARD="" + +for OFFSET in $(seq 0 15); do + H=$((HEAD - OFFSET)) + SHARD="$(curl -s "https://mainnet.neardata.xyz/v0/block/$H" \ + "${AUTH_HEADER[@]}" \ + | jq -r --arg contract "$TARGET_CONTRACT" ' + .shards[] + | select([.state_changes[]? | select(.change.account_id? == $contract)] | length > 0) + | .shard_id + ' | head -1)" + if [ -n "$SHARD" ]; then + FOUND_HEIGHT=$H; FOUND_SHARD=$SHARD + break + fi +done + +if [ -z "$FOUND_HEIGHT" ]; then + echo "no state mutation for $TARGET_CONTRACT in the last 16 finalized blocks" +else + curl -s "https://mainnet.neardata.xyz/v0/block/$FOUND_HEIGHT/shard/$FOUND_SHARD" \ + "${AUTH_HEADER[@]}" \ + | jq --arg contract "$TARGET_CONTRACT" --argjson height "$FOUND_HEIGHT" --argjson shard_id "$FOUND_SHARD" '{ + height: $height, + shard_id: $shard_id, + state_changes: [.state_changes[] | select(.change.account_id? == $contract) | {type, cause: (.cause | keys[0])}][0:3], + execution_outcomes: [.receipt_execution_outcomes[] | select(.execution_outcome.outcome.executor_id == $contract) | {receipt_id: .execution_outcome.id, status: (.execution_outcome.outcome.status | keys[0])}][0:3] + }' +fi +``` + +На mainnet `intents.near` живёт на shard 7, поэтому обход назад обычно попадает в цель за несколько блоков. Payload shard называет конкретные типы state-change (`account_update`, `data_update` и т. п.) и результаты receipt, которые их породили, — shard-локальное доказательство без догадок. Для менее активных контрактов расширьте диапазон `OFFSET`. + +## Когда расширить поверхность + +- Используйте [Transactions API](https://docs.fastnear.com/ru/tx), когда у вас уже есть `tx_hash` и нужна человекочитаемая история транзакции. +- Используйте [RPC Reference](https://docs.fastnear.com/ru/rpc), когда следующий вопрос касается точной протокольной семантики receipt или блока. +- Используйте [Block Headers](https://docs.fastnear.com/ru/neardata/block-headers), когда нужна только динамика head/finality, а не проверка contract-touch. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/examples/index.md b/static/ru/neardata/examples/index.md new file mode 100644 index 0000000..3639e91 --- /dev/null +++ b/static/ru/neardata/examples/index.md @@ -0,0 +1,147 @@ +**Источник:** [https://docs.fastnear.com/ru/neardata/examples](https://docs.fastnear.com/ru/neardata/examples) + +## Примеры + +NEAR Data возвращает каждый блок полностью гидратированным одним JSON-документом — header плюс per-shard chunks, receipts, результаты исполнения и state changes, — так что один `curl` уже даёт всё необходимое, чтобы отфильтровать нужный контракт без второго запроса. + +Все shell-примеры ниже работают на публичных NEAR Data-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### На каком блоке NEAR сейчас? + +`/v0/last_block/final` отдаёт 302-редирект на текущий финализированный блок. Прежде чем фильтровать по конкретному контракту, полезно увидеть, как выглядит один блок на уровне протокола: транзакции приходят с разбивкой по shard, поэтому общее число транзакций в блоке — это сумма по shards, а не одно поле верхнего уровня. + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" \ + | jq '{ + height: .block.header.height, + timestamp_nanosec: .block.header.timestamp_nanosec, + txs_per_shard: [.shards[] | {shard_id, tx_count: (.chunk.transactions | length)}], + total_txs: ([.shards[].chunk.transactions[]?] | length) + }' +``` + +Живой блок показывает 9 shards и горсть транзакций, распределённых по ним — большинство shards в любом блоке пустые, а активность концентрируется на тех shards, где живут загруженные контракты. `timestamp_nanosec` — это Unix-время в наносекундах (делите на 1e9, чтобы получить секунды). С этим одним вызовом у вас уже есть всё необходимое для дальнейшего копания — примеры фильтрации ниже просто применяют jq к тому же ответу. + +### Был ли мой контракт затронут в последнем финализированном блоке? + +`/v0/last_block/final` отдаёт 302-редирект на текущий финализированный блок. Контракт может проявиться либо в `transactions` chunk (когда он `receiver_id`), либо в `receipts` (когда прилетает cross-shard-вызов), поэтому один проход jq по shards покрывает оба случая. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" \ + | jq --arg contract "$TARGET_CONTRACT" '{ + height: .block.header.height, + contract: $contract, + touched_shards: [ + .shards[] | { + shard_id, + txs: [.chunk.transactions[]? | select(.transaction.receiver_id == $contract) | .transaction.hash], + receipts: [.chunk.receipts[]? | select(.receiver_id == $contract) | .receipt_id] + } | select((.txs | length) + (.receipts | length) > 0) + ] + }' +``` + +`touched_shards: []` — полный ответ для тихого блока. Непустой список называет shards, где контракт появился, и отдаёт конкретные `tx`-хеши или `receipt_id` — передавайте хеш в [Transactions API](https://docs.fastnear.com/ru/tx), когда нужна человекочитаемая история. Receipts без парных `txs` — это нормально: cross-contract-вызов приходит как incoming receipt в этом блоке, даже если исходная транзакция была раньше. + +### Увидел ли я активность в optimistic-режиме, и догнала ли её finality? + +Optimistic-блоки ходят по `/v0/block_opt/{height}` примерно на секунду впереди `/v0/block/{height}`. Цикл мониторинга может действовать по optimistic-сигналу и ожидать, что тот же ответ придёт на финализированный эндпоинт через один блок — если только стресс сети не расширит разрыв, и тогда финализированный fetch вернёт `null`, а вы подождёте. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +count_touches() { + jq --arg contract "$1" ' + [.shards[] + | ([.chunk.transactions[]? | select(.transaction.receiver_id == $contract)] | length) + + ([.chunk.receipts[]? | select(.receiver_id == $contract)] | length)] + | add // 0' +} + +OPT_LOCATION="$( + curl -s -D - -o /dev/null "${AUTH_HEADER[@]}" "https://mainnet.neardata.xyz/v0/last_block/optimistic" \ + | awk 'tolower($1) == "location:" {print $2}' | tr -d '\r' +)" +OPT_HEIGHT="${OPT_LOCATION##*/}" + +echo "optimistic @ $OPT_HEIGHT: $(curl -s "https://mainnet.neardata.xyz$OPT_LOCATION" \ + "${AUTH_HEADER[@]}" | count_touches "$TARGET_CONTRACT") touches" +FINAL="$(curl -s "https://mainnet.neardata.xyz/v0/block/$OPT_HEIGHT" \ + "${AUTH_HEADER[@]}")" +if [ "$(printf '%s' "$FINAL" | jq 'type')" = '"null"' ]; then + echo "finalized @ $OPT_HEIGHT: not caught up yet" +else + echo "finalized @ $OPT_HEIGHT: $(printf '%s' "$FINAL" | count_touches "$TARGET_CONTRACT") touches" +fi +``` + +На здоровом mainnet оба счётчика совпадают в пределах секунды. Ценность — в самом шаблоне: optimistic-поток даёт ответ, на который можно реагировать сразу, а финализированный приходит через блок как надёжное подтверждение. + +### Какой shard действительно изменил состояние моего контракта? + +В большинстве финализированных блоков нет мутации состояния ни для одного конкретного контракта — активность разрежена и привязана к shard. Идите назад от финализированной головы, пока состояние контракта реально не изменится, и откройте этот shard для payload мутации. Вызов уровня блока говорит, *на каком* shard это случилось; вызов уровня shard — *как*. + +```bash +TARGET_CONTRACT=intents.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +HEAD="$(curl -sL "https://mainnet.neardata.xyz/v0/last_block/final" \ + "${AUTH_HEADER[@]}" | jq '.block.header.height')" +FOUND_HEIGHT="" +FOUND_SHARD="" + +for OFFSET in $(seq 0 15); do + H=$((HEAD - OFFSET)) + SHARD="$(curl -s "https://mainnet.neardata.xyz/v0/block/$H" \ + "${AUTH_HEADER[@]}" \ + | jq -r --arg contract "$TARGET_CONTRACT" ' + .shards[] + | select([.state_changes[]? | select(.change.account_id? == $contract)] | length > 0) + | .shard_id + ' | head -1)" + if [ -n "$SHARD" ]; then + FOUND_HEIGHT=$H; FOUND_SHARD=$SHARD + break + fi +done + +if [ -z "$FOUND_HEIGHT" ]; then + echo "no state mutation for $TARGET_CONTRACT in the last 16 finalized blocks" +else + curl -s "https://mainnet.neardata.xyz/v0/block/$FOUND_HEIGHT/shard/$FOUND_SHARD" \ + "${AUTH_HEADER[@]}" \ + | jq --arg contract "$TARGET_CONTRACT" --argjson height "$FOUND_HEIGHT" --argjson shard_id "$FOUND_SHARD" '{ + height: $height, + shard_id: $shard_id, + state_changes: [.state_changes[] | select(.change.account_id? == $contract) | {type, cause: (.cause | keys[0])}][0:3], + execution_outcomes: [.receipt_execution_outcomes[] | select(.execution_outcome.outcome.executor_id == $contract) | {receipt_id: .execution_outcome.id, status: (.execution_outcome.outcome.status | keys[0])}][0:3] + }' +fi +``` + +На mainnet `intents.near` живёт на shard 7, поэтому обход назад обычно попадает в цель за несколько блоков. Payload shard называет конкретные типы state-change (`account_update`, `data_update` и т. п.) и результаты receipt, которые их породили, — shard-локальное доказательство без догадок. Для менее активных контрактов расширьте диапазон `OFFSET`. + +## Когда расширить поверхность + +- Используйте [Transactions API](https://docs.fastnear.com/ru/tx), когда у вас уже есть `tx_hash` и нужна человекочитаемая история транзакции. +- Используйте [RPC Reference](https://docs.fastnear.com/ru/rpc), когда следующий вопрос касается точной протокольной семантики receipt или блока. +- Используйте [Block Headers](https://docs.fastnear.com/ru/neardata/block-headers), когда нужна только динамика head/finality, а не проверка contract-touch. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/first-block.md b/static/ru/neardata/first-block.md index dc1c366..09401f7 100644 --- a/static/ru/neardata/first-block.md +++ b/static/ru/neardata/first-block.md @@ -1843,3 +1843,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/first-block/index.md b/static/ru/neardata/first-block/index.md index dc1c366..09401f7 100644 --- a/static/ru/neardata/first-block/index.md +++ b/static/ru/neardata/first-block/index.md @@ -1843,3 +1843,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/index.md b/static/ru/neardata/index.md index 8e11085..29a87d5 100644 --- a/static/ru/neardata/index.md +++ b/static/ru/neardata/index.md @@ -2,7 +2,7 @@ # NEAR Data API -NEAR Data API — это поверхность для чтения данных почти в реальном времени, а также по семействам блоков. Используйте её, когда нужны свежие срезы блоков, вспомогательные маршруты с перенаправлением или недавние финализированные и оптимистичные чтения, но без позиционирования продукта как потокового сервиса. +NEAR Data API — это поверхность для недавних блоков и шардов. Используйте её, когда нужны свежие срезы блоков, мониторинг активности контракта, вспомогательные маршруты с перенаправлением или сравнение оптимистичных и финализированных чтений без превращения продукта в потоковый API. ## Базовые URL @@ -17,8 +17,9 @@ https://testnet.neardata.xyz ## Лучше всего подходит для - опроса недавних финализированных и оптимистичных блоков; -- вспомогательных маршрутов по блокам и сценариев с перенаправлением; -- лёгких проверок свежести данных и мониторинга. +- обнаружения того, появился ли живой контракт в недавнем блоке и изменил ли он состояние; +- сравнения оптимистичного сигнала с финализированным подтверждением; +- проверки одного недавнего шарда, когда уже известно, какой блок важен. ## Когда его не стоит использовать @@ -33,9 +34,14 @@ https://testnet.neardata.xyz ## С чего обычно начинают -- [Оптимистичный блок](https://docs.fastnear.com/ru/neardata/block-optimistic) — для самого свежего опроса блоков. -- [Финализированный блок по высоте](https://docs.fastnear.com/ru/neardata/block) и [Заголовки блока](https://docs.fastnear.com/ru/neardata/block-headers) — для запросов по финализированным блокам. -- [Перенаправление на последний финализированный блок](https://docs.fastnear.com/ru/neardata/last-block-final) и [Перенаправление на последний оптимистичный блок](https://docs.fastnear.com/ru/neardata/last-block-optimistic) — когда нужны вспомогательные маршруты с перенаправлением. +- [Перенаправление на последний финализированный блок](https://docs.fastnear.com/ru/neardata/last-block-final) и [Перенаправление на последний оптимистичный блок](https://docs.fastnear.com/ru/neardata/last-block-optimistic) — когда нужно быстро узнать самый новый недавний блок. +- [Финализированный блок по высоте](https://docs.fastnear.com/ru/neardata/block) — когда нужен один недавний гидратированный блок с уже приложенными данными по шардам. +- [Шард блока](https://docs.fastnear.com/ru/neardata/block-shard) — когда недавний блок уже показал нужный шард и его надо разобрать глубже. +- [Заголовки блока](https://docs.fastnear.com/ru/neardata/block-headers) — когда важнее движение головы цепочки и финальности, а не широкий блоковый документ. + +## Нужен сценарий? + +Используйте [примеры NEAR Data API](https://docs.fastnear.com/ru/neardata/examples) для практических примеров: обнаружения активности контракта, сравнения оптимистичных и финализированных наблюдений, а также проверки изменений на уровне шарда. ## Устранение неполадок @@ -50,3 +56,10 @@ https://testnet.neardata.xyz ### Нужна потоковая передача, а не опрос Эта поверхность предназначена для чтения через опрос почти в реальном времени. Не позиционируйте её как продукт на основе WebSocket или вебхуков. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/last-block-final.md b/static/ru/neardata/last-block-final.md index ed854bf..021b228 100644 --- a/static/ru/neardata/last-block-final.md +++ b/static/ru/neardata/last-block-final.md @@ -1843,3 +1843,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/last-block-final/index.md b/static/ru/neardata/last-block-final/index.md index ed854bf..021b228 100644 --- a/static/ru/neardata/last-block-final/index.md +++ b/static/ru/neardata/last-block-final/index.md @@ -1843,3 +1843,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/last-block-optimistic.md b/static/ru/neardata/last-block-optimistic.md index 81ca60c..7f27b7d 100644 --- a/static/ru/neardata/last-block-optimistic.md +++ b/static/ru/neardata/last-block-optimistic.md @@ -1843,3 +1843,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/last-block-optimistic/index.md b/static/ru/neardata/last-block-optimistic/index.md index 81ca60c..7f27b7d 100644 --- a/static/ru/neardata/last-block-optimistic/index.md +++ b/static/ru/neardata/last-block-optimistic/index.md @@ -1843,3 +1843,10 @@ "refName": "BlockDocument" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/system/health.md b/static/ru/neardata/system/health.md index e565e6c..38e08dd 100644 --- a/static/ru/neardata/system/health.md +++ b/static/ru/neardata/system/health.md @@ -59,3 +59,10 @@ "refName": "HealthResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/neardata/system/health/index.md b/static/ru/neardata/system/health/index.md index e565e6c..38e08dd 100644 --- a/static/ru/neardata/system/health/index.md +++ b/static/ru/neardata/system/health/index.md @@ -59,3 +59,10 @@ "refName": "HealthResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/redocly-config.md b/static/ru/redocly-config.md index de9f065..639f299 100644 --- a/static/ru/redocly-config.md +++ b/static/ru/redocly-config.md @@ -48,3 +48,10 @@ Bearer-токены по-прежнему используют: - `mike-docs/README.md` - `mike-docs/INTEGRATION_GUIDE.md` - `builder-docs/CLAUDE.md` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/redocly-config/index.md b/static/ru/redocly-config/index.md index de9f065..639f299 100644 --- a/static/ru/redocly-config/index.md +++ b/static/ru/redocly-config/index.md @@ -48,3 +48,10 @@ Bearer-токены по-прежнему используют: - `mike-docs/README.md` - `mike-docs/INTEGRATION_GUIDE.md` - `builder-docs/CLAUDE.md` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc.md b/static/ru/rpc.md index 6bd09fc..7e0b256 100644 --- a/static/ru/rpc.md +++ b/static/ru/rpc.md @@ -35,6 +35,10 @@ https://archival-rpc.testnet.fastnear.com - [`send_tx`](https://docs.fastnear.com/ru/rpc/transaction/send-tx) — отправка транзакций; [`tx`](https://docs.fastnear.com/ru/rpc/transaction/tx-status) — статус исполнения. - [`validators`](https://docs.fastnear.com/ru/rpc/validators/validators-current) — валидаторы текущей эпохи. +## Нужен сценарий? + +Используйте [примеры RPC](https://docs.fastnear.com/ru/rpc/examples) для практических примеров: точных проверок состояния, анализа блоков, view-вызовов контрактов и отправки транзакций с подтверждением. + ## Используйте RPC, когда - нужны канонические формы запросов и ответов из протокола; @@ -76,3 +80,10 @@ https://archival-rpc.testnet.fastnear.com ### Мне нужен более простой ответ, чем даёт JSON-RPC Обычно это означает, что нужно индексированное REST-семейство, а не сырой RPC. Воспользуйтесь страницей выбора поверхности и подберите более высокий уровень абстракции. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/account/view-access-key-list.md b/static/ru/rpc/account/view-access-key-list.md index e801e5f..4fc29a8 100644 --- a/static/ru/rpc/account/view-access-key-list.md +++ b/static/ru/rpc/account/view-access-key-list.md @@ -237,3 +237,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/account/view-access-key-list/index.md b/static/ru/rpc/account/view-access-key-list/index.md index e801e5f..4fc29a8 100644 --- a/static/ru/rpc/account/view-access-key-list/index.md +++ b/static/ru/rpc/account/view-access-key-list/index.md @@ -237,3 +237,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/account/view-access-key.md b/static/ru/rpc/account/view-access-key.md index 3ac1bee..929e0c4 100644 --- a/static/ru/rpc/account/view-access-key.md +++ b/static/ru/rpc/account/view-access-key.md @@ -255,3 +255,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/account/view-access-key/index.md b/static/ru/rpc/account/view-access-key/index.md index 3ac1bee..929e0c4 100644 --- a/static/ru/rpc/account/view-access-key/index.md +++ b/static/ru/rpc/account/view-access-key/index.md @@ -255,3 +255,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/account/view-account.md b/static/ru/rpc/account/view-account.md index c3b9b91..8e47621 100644 --- a/static/ru/rpc/account/view-account.md +++ b/static/ru/rpc/account/view-account.md @@ -289,3 +289,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/account/view-account/index.md b/static/ru/rpc/account/view-account/index.md index c3b9b91..8e47621 100644 --- a/static/ru/rpc/account/view-account/index.md +++ b/static/ru/rpc/account/view-account/index.md @@ -289,3 +289,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/block/block-by-height.md b/static/ru/rpc/block/block-by-height.md index 6cd45c7..2d381c3 100644 --- a/static/ru/rpc/block/block-by-height.md +++ b/static/ru/rpc/block/block-by-height.md @@ -191,3 +191,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/block/block-by-height/index.md b/static/ru/rpc/block/block-by-height/index.md index 6cd45c7..2d381c3 100644 --- a/static/ru/rpc/block/block-by-height/index.md +++ b/static/ru/rpc/block/block-by-height/index.md @@ -191,3 +191,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/block/block-by-id.md b/static/ru/rpc/block/block-by-id.md index f8ac3ed..587b9fc 100644 --- a/static/ru/rpc/block/block-by-id.md +++ b/static/ru/rpc/block/block-by-id.md @@ -191,3 +191,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/block/block-by-id/index.md b/static/ru/rpc/block/block-by-id/index.md index f8ac3ed..587b9fc 100644 --- a/static/ru/rpc/block/block-by-id/index.md +++ b/static/ru/rpc/block/block-by-id/index.md @@ -191,3 +191,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/block/block-effects.md b/static/ru/rpc/block/block-effects.md index ba4fbad..9f7963d 100644 --- a/static/ru/rpc/block/block-effects.md +++ b/static/ru/rpc/block/block-effects.md @@ -225,3 +225,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/block/block-effects/index.md b/static/ru/rpc/block/block-effects/index.md index ba4fbad..9f7963d 100644 --- a/static/ru/rpc/block/block-effects/index.md +++ b/static/ru/rpc/block/block-effects/index.md @@ -225,3 +225,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/contract/call-function.md b/static/ru/rpc/contract/call-function.md index 566fdc7..ff0e9ea 100644 --- a/static/ru/rpc/contract/call-function.md +++ b/static/ru/rpc/contract/call-function.md @@ -272,3 +272,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/contract/call-function/index.md b/static/ru/rpc/contract/call-function/index.md index 566fdc7..ff0e9ea 100644 --- a/static/ru/rpc/contract/call-function/index.md +++ b/static/ru/rpc/contract/call-function/index.md @@ -272,3 +272,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/contract/view-code.md b/static/ru/rpc/contract/view-code.md index cc81306..c893261 100644 --- a/static/ru/rpc/contract/view-code.md +++ b/static/ru/rpc/contract/view-code.md @@ -242,3 +242,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/contract/view-code/index.md b/static/ru/rpc/contract/view-code/index.md index cc81306..c893261 100644 --- a/static/ru/rpc/contract/view-code/index.md +++ b/static/ru/rpc/contract/view-code/index.md @@ -242,3 +242,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/contract/view-global-contract-code-by-account-id.md b/static/ru/rpc/contract/view-global-contract-code-by-account-id.md index bc45bc2..a5a8282 100644 --- a/static/ru/rpc/contract/view-global-contract-code-by-account-id.md +++ b/static/ru/rpc/contract/view-global-contract-code-by-account-id.md @@ -242,3 +242,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/contract/view-global-contract-code-by-account-id/index.md b/static/ru/rpc/contract/view-global-contract-code-by-account-id/index.md index bc45bc2..a5a8282 100644 --- a/static/ru/rpc/contract/view-global-contract-code-by-account-id/index.md +++ b/static/ru/rpc/contract/view-global-contract-code-by-account-id/index.md @@ -242,3 +242,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/contract/view-global-contract-code.md b/static/ru/rpc/contract/view-global-contract-code.md index 78908f1..587b503 100644 --- a/static/ru/rpc/contract/view-global-contract-code.md +++ b/static/ru/rpc/contract/view-global-contract-code.md @@ -242,3 +242,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/contract/view-global-contract-code/index.md b/static/ru/rpc/contract/view-global-contract-code/index.md index 78908f1..587b503 100644 --- a/static/ru/rpc/contract/view-global-contract-code/index.md +++ b/static/ru/rpc/contract/view-global-contract-code/index.md @@ -242,3 +242,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/contract/view-state.md b/static/ru/rpc/contract/view-state.md index 4731913..f23099c 100644 --- a/static/ru/rpc/contract/view-state.md +++ b/static/ru/rpc/contract/view-state.md @@ -268,3 +268,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/contract/view-state/index.md b/static/ru/rpc/contract/view-state/index.md index 4731913..f23099c 100644 --- a/static/ru/rpc/contract/view-state/index.md +++ b/static/ru/rpc/contract/view-state/index.md @@ -268,3 +268,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/examples.md b/static/ru/rpc/examples.md new file mode 100644 index 0000000..7d6cbcd --- /dev/null +++ b/static/ru/rpc/examples.md @@ -0,0 +1,303 @@ +**Источник:** [https://docs.fastnear.com/ru/rpc/examples](https://docs.fastnear.com/ru/rpc/examples) + +# Примеры RPC + +Начинайте с RPC-метода, который отвечает на вопрос. Используйте `tx`, чтобы отследить включение и финальность по хешу транзакции, и расширяйте поверхность только когда нужны дерево receipts, сырой state или трассировка на уровне shard. + +Все shell-примеры ниже работают на публичных RPC-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +## Состояние аккаунта + +### Показать баланс и storage аккаунта на finality + +`view_account` — канонический RPC-запрос для текущего состояния аккаунта. Один вызов возвращает свободный баланс, сумму, заблокированную в валидаторском стейке или lockup-контракте, использованное storage и блок, на котором было сделано чтение. `finality: "final"` гарантирует, что вы читаете стабильное состояние, а не optimistic-представление. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.mainnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_account",account_id:$account_id,finality:"final"} + }')" \ + | jq '.result | {amount, locked, storage_usage, block_height, block_hash}' +``` + +Для `root.near` это возвращает `amount` (yoctoNEAR в свободной части), `locked: "0"` (ничего в валидаторском стейке или lockup-контракте) и `storage_usage: 28677` — примерно 28.7 КБ on-chain-состояния. Пара `block_height`/`block_hash` фиксирует точку чтения; чтобы прочитать несколько аккаунтов *на одном и том же* блоке, переиспользуйте возвращённый `block_hash` как `block_id` в последующих запросах. + +## Включение транзакции и финальность + +### Отследить транзакцию от хеша до финальности + +Есть tx hash? Опрашивайте `tx` с минимальным порогом `wait_until`, который отвечает на ваш вопрос. + +```bash +TX_HASH=CVyG2xLJ6fuKCtULAxMnWTh2GL5ey2UUiTcgYT3M6Pow +SIGNER_ACCOUNT_ID=mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://archival-rpc.testnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" --arg signer_id "$SIGNER_ACCOUNT_ID" '{ + jsonrpc: "2.0", id: "fastnear", method: "tx", + params: {tx_hash: $tx_hash, sender_account_id: $signer_id, wait_until: "INCLUDED"} + }')" \ + | jq '{ + asked: "INCLUDED", + final_execution_status: .result.final_execution_status, + status_class: (.result.status | keys[0]), + receipts_outcome_count: (.result.receipts_outcome | length) + }' +``` + +Для зафиксированной исторической транзакции (1-yocto self-transfer от `mike.testnet`) ответ возвращается как `FINAL`, хотя мы спрашивали `INCLUDED`. Правило такое: **`wait_until` — это минимальный порог, а не целевой**. Узел возвращает тот этап, которого транзакция действительно достигла: для исторической всегда `FINAL`; для полётной выбирайте `INCLUDED`, когда достаточно включения и нужен самый ранний возврат, или `FINAL`, когда реальный вопрос звучит «завершилась ли?». + +Два перехода отсюда: + +- **Отправляете в реальном времени?** [`broadcast_tx_async`](https://docs.fastnear.com/ru/rpc/transaction/broadcast-tx-async) возвращает хеш сразу после того, как узел принял payload — отслеживайте отдельно через `tx`. [`send_tx`](https://docs.fastnear.com/ru/rpc/transaction/send-tx) одновременно отправляет и блокируется на выбранном `wait_until` в одном запросе. +- **Нужно дерево receipts, а не только outcome?** `tx` уже включает `receipts_outcome`; расширяйте поверхность до [`EXPERIMENTAL_tx_status`](https://docs.fastnear.com/ru/rpc/transaction/experimental-tx-status) только тогда, когда дополнительно нужны сырые записи receipts. + +## Инспекция блока на tip + +### Описать первый action первой транзакции на текущем tip + +Блок NEAR — это header поверх N shard chunks, а не плоский список транзакций. `block` возвращает headers chunks; сами транзакции лежат уровнем ниже, внутри `chunk`. Шортката `block → tx` нет — блок не несёт хешей транзакций, поэтому `tx` (которому нужен hash) в этой цепочке не участвует. Канонический проход — `status` → `block` → `chunk`, пропуская пустые chunks по дороге. Большинство chunks в tip-блоке пустые — их `tx_root` равен сентинелу `11111111111111111111111111111111`, поэтому селектору нужен фильтр. + +```bash +EMPTY_TX_ROOT=11111111111111111111111111111111 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +BLOCK_HASH="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data '{"jsonrpc":"2.0","id":"fastnear","method":"status","params":[]}' \ + | jq -r '.result.sync_info.latest_block_hash')" + +CHUNK_HASH="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg block_hash "$BLOCK_HASH" '{ + jsonrpc:"2.0",id:"fastnear",method:"block",params:{block_id:$block_hash} + }')" \ + | jq -r --arg empty "$EMPTY_TX_ROOT" ' + first(.result.chunks[] | select(.tx_root != $empty) | .chunk_hash) // empty')" + +if [ -z "$CHUNK_HASH" ]; then + echo "tip block had no transactions in any chunk — rerun on the next head" +else + curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg chunk_hash "$CHUNK_HASH" '{ + jsonrpc:"2.0",id:"fastnear",method:"chunk",params:{chunk_id:$chunk_hash} + }')" \ + | jq '{ + chunk_shard: .result.header.shard_id, + chunk_height: .result.header.height_included, + first_tx: { + hash: .result.transactions[0].hash, + signer_id: .result.transactions[0].signer_id, + receiver_id: .result.transactions[0].receiver_id + }, + first_action: ( + .result.transactions[0].actions[0] as $a + | if ($a | type) == "string" then {kind: $a} + elif $a.FunctionCall then {kind: "FunctionCall", method_name: $a.FunctionCall.method_name} + else {kind: ($a | keys[0])} end + ) + }' +fi +``` + +Живой запуск возвращает первый chunk текущего tip, первую транзакцию и первый action — часто это `FunctionCall` на контракте моста или tg-бота (mainnet активен). Tip-блок может быть валидным и при этом не содержать транзакций ни в одном chunk — поэтому ветка с пустым результатом остаётся; это честный ответ для тихого момента сети. + +## Механика аккаунтов и ключей + +### Определить function-call-ключи, которые стоит удалить + +Каждый кошелёк, шлюз и dapp-сессия, в которую вы заходите, обычно оставляет за собой function-call-ключ. Большинством из них вы больше никогда не воспользуетесь. `view_access_key_list` возвращает все ключи аккаунта; структура nonce показывает, какие из них устарели. + +Новые ключи стартуют с `block_height * 10^6`, и значение инкрементируется на единицу за каждую транзакцию, которую ключ подписывает, поэтому: + +- `nonce / 10^6` → блок, в котором ключ был добавлен +- `nonce % 10^6` → сколько раз ключ был использован + +Любой ключ с `tx_count: 0` был создан и ни разу не использовался — самый очевидный кандидат на очистку. Следующий по порядку — ключи, заскоупленные на контракт, с которым вы больше не работаете. Фильтр ниже сужает до `social.near`, но чтобы аудитировать другой контракт, меняется только строка `RECEIVER_ID`. + +```bash +ACCOUNT_ID=root.near +RECEIVER_ID=social.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.mainnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_access_key_list",account_id:$account_id,finality:"final"} + }')" \ + | jq --arg receiver "$RECEIVER_ID" ' + { + total_keys: (.result.keys | length), + fcks_for_receiver: [ + .result.keys[] + | select((.access_key.permission | type) == "object") + | select(.access_key.permission.FunctionCall.receiver_id == $receiver) + | { + public_key, + added_at_block: (.access_key.nonce / 1000000 | floor), + tx_count: (.access_key.nonce % 1000000), + method_names: (.access_key.permission.FunctionCall.method_names | if . == [] then "ANY" else . end), + allowance: (.access_key.permission.FunctionCall.allowance // "unlimited") + } + ] | sort_by(.tx_count) + }' +``` + +Для `root.near` это возвращает 235 ключей всего, включая 34 function-call-ключа на `social.near`; 21 из них были созданы и ни разу не использовались (`tx_count: 0`) и потому являются прямыми кандидатами на удаление. `method_names: "ANY"` означает, что ключ может вызвать любой метод на `social.near`; сужение до списка вида `["find_grants", "insert_grant", "delete_grant"]` означает, что ключ был заскоуплен на write-поверхность одного dapp. + +Чтобы удалить такой ключ, подпишите action `DeleteKey` **full-access**-ключом (function-call-ключ не может авторизовать `DeleteKey`) и отправьте через [`send_tx`](https://docs.fastnear.com/ru/rpc/transaction/send-tx). Повторный запуск того же запроса подтвердит, что ключа больше нет. + +## Чтение контрактов и сырой state + +### Прочитать storage контракта, не запуская его + +View-метод вроде `get_num` всё равно заставляет узел загрузить wasm-контракта и выполнить его. Если ключ storage уже известен, `view_state` возвращает сырые сериализованные байты напрямую — без исполнения и без зависимости от того, выставил ли контракт getter для этого поля вообще. + +Контракты на `near-sdk-rs` хранят верхнеуровневую `#[near_bindgen]`-структуру под ключом `STATE`. Передайте `STATE` как `prefix_base64` (`U1RBVEU=` — это base64 тех же четырёх ASCII-байт), и узел вернёт сериализованное значение. + +```bash +CONTRACT_ID=counter.near-examples.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +RAW_B64="$(curl -s "https://rpc.testnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg contract "$CONTRACT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_state",account_id:$contract,prefix_base64:"U1RBVEU=",finality:"final"} + }')" \ + | jq -r '.result.values[0].value')" + +DECODED_I8="$(python3 -c "import base64; print(int.from_bytes(base64.b64decode('$RAW_B64'),'little',signed=True))")" + +jq -n --arg raw "$RAW_B64" --argjson val "$DECODED_I8" '{raw_bytes_base64: $raw, decoded_i8: $val}' +``` + +Для живого counter это возвращает `"CQ=="` — один байт `0x09`, декодируется как signed i8 в `9`. Это то же число, которое вернул бы `get_num`, только прочитанное прямо из trie без запуска кода контракта. `signed=True` важен: отрицательный counter сериализовался бы как `"/w=="` (байт `0xff` → i8 `-1`, а не u8 `255`). + +Тянитесь к `view_state`, когда контракт не выставляет view-метод для нужных данных или когда нужна семья ключей, которую контракт не публикует. Для большинства чтений `call_function` всё равно требует меньше церемоний. Если вопрос становится историческим, а не текущим, расширяйте поверхность до [KV FastData API](https://docs.fastnear.com/ru/fastdata/kv). + +## NEAR Social и точные чтения BOS + +Оставайтесь на точных чтениях SocialDB и on-chain-проверках готовности — пока вопрос не станет историческим. + +### Может ли этот аккаунт прямо сейчас публиковать в NEAR Social? + +`social.near` знает две вещи, о которых UI кошелька может только догадываться: сколько storage осталось у каждого аккаунта и разрешена ли делегированному signer запись под этим аккаунтом. Два view-вызова сворачивают вопрос готовности к одному boolean. + +```bash +ACCOUNT_ID=root.near # account you're writing under +SIGNER_ACCOUNT_ID=root.near # account signing the transaction +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +STORAGE_ARGS_B64="$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id:$account_id}' | base64 | tr -d '\n')" + +STORAGE="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$STORAGE_ARGS_B64" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"get_account_storage",args_base64:$args,finality:"final"} + }')" \ + | jq '.result.result | implode | fromjson')" + +if [ "$SIGNER_ACCOUNT_ID" = "$ACCOUNT_ID" ]; then + PERMISSION=true +else + PERM_ARGS_B64="$(jq -nc --arg pred "$SIGNER_ACCOUNT_ID" --arg key "$ACCOUNT_ID" '{predecessor_id:$pred,key:$key}' | base64 | tr -d '\n')" + PERMISSION="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$PERM_ARGS_B64" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"is_write_permission_granted",args_base64:$args,finality:"final"} + }')" \ + | jq '.result.result | implode | fromjson')" +fi + +jq -n --argjson storage "$STORAGE" --argjson permission "$PERMISSION" \ + --arg account_id "$ACCOUNT_ID" --arg signer "$SIGNER_ACCOUNT_ID" '{ + account_id: $account_id, + signer_account_id: $signer, + storage: $storage, + permission_granted: $permission, + ready_to_publish: (($storage.available_bytes // 0) > 0 and $permission) + }' +``` + +Для `root.near`, подписывающего под собой, это возвращает `storage: {used_bytes: 136245, available_bytes: 42484}`, `permission_granted: true` (владельческая запись) и `ready_to_publish: true`. Если `storage` приходит как `null` или `available_bytes: 0`, аккаунту нужен `storage_deposit` на `social.near`, прежде чем новая запись сможет закрепиться. Если signer отличается от цели, ветка permission спрашивает `is_write_permission_granted({predecessor_id, key})` — тот же on-chain-ответ, который dapp видит, прежде чем писать от имени пользователя. Полную поверхность контракта см. в [SocialDB API](https://github.com/NearSocial/social-db#api). + +### Что `mob.near/widget/Profile` содержит прямо сейчас? + +SocialDB хранит BOS-виджеты как ключи `/widget/` на `social.near`. Один `keys` с типом возврата `BlockHeight` возвращает каталог плюс якоря последней записи по каждому виджету; один `get` возвращает точный исходник. + +```bash +ACCOUNT_ID=mob.near +WIDGET_NAME=Profile +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +KEYS_ARGS="$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + keys: [($account_id + "/widget/*")], + options: {return_type: "BlockHeight"} +}' | base64 | tr -d '\n')" + +curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$KEYS_ARGS" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"keys",args_base64:$args,finality:"final"} + }')" \ + | jq --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" ' + .result.result | implode | fromjson | .[$account_id].widget as $map + | { + total_widgets: ($map | length), + most_recently_written: ($map | to_entries | sort_by(-.value) | .[0:5] | map({widget: .key, last_write_block: .value})), + target_last_write_block: $map[$widget] + }' + +GET_ARGS="$(jq -nc --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" '{ + keys: [($account_id + "/widget/" + $widget)] +}' | base64 | tr -d '\n')" + +curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$GET_ARGS" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"get",args_base64:$args,finality:"final"} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" ' + .result.result | implode | fromjson | .[$account_id].widget[$widget] | split("\n")[0:20] | join("\n")' +``` + +Для `mob.near` каталог показывает 264 виджета; `Profile` последний раз записывался в блоке `86494825` — годами ранее, стабильно с тех пор — и исходник начинается с `const accountId = props.accountId ?? context.accountId;`. Тип возврата `BlockHeight` ничего не стоит дополнительно и превращает листинг ключей в дешёвую проверку актуальности. Сохраните блок последней записи, если позже захотите доказать, *какая транзакция* записала именно эту версию — передайте его в [Расширенный поиск записи SocialDB](https://docs.fastnear.com/ru/tx/socialdb-proofs). + +## Частые ошибки + +- Начинать в RPC, когда пользователю нужна сводка по активам или индексированная история. +- Забывать переключаться с обычного RPC на archival RPC для более старого state. +- Считать browser auth в UI документации продовым backend-паттерном. +- Оставаться в низкоуровневых вызовах статуса транзакции, когда вопрос уже стал forensic или историческим. + +## Связанные страницы + +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [Auth & Access](https://docs.fastnear.com/ru/auth) +- [FastNear API](https://docs.fastnear.com/ru/api) +- [Transactions API](https://docs.fastnear.com/ru/tx) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/examples/index.md b/static/ru/rpc/examples/index.md new file mode 100644 index 0000000..7d6cbcd --- /dev/null +++ b/static/ru/rpc/examples/index.md @@ -0,0 +1,303 @@ +**Источник:** [https://docs.fastnear.com/ru/rpc/examples](https://docs.fastnear.com/ru/rpc/examples) + +# Примеры RPC + +Начинайте с RPC-метода, который отвечает на вопрос. Используйте `tx`, чтобы отследить включение и финальность по хешу транзакции, и расширяйте поверхность только когда нужны дерево receipts, сырой state или трассировка на уровне shard. + +Все shell-примеры ниже работают на публичных RPC-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +## Состояние аккаунта + +### Показать баланс и storage аккаунта на finality + +`view_account` — канонический RPC-запрос для текущего состояния аккаунта. Один вызов возвращает свободный баланс, сумму, заблокированную в валидаторском стейке или lockup-контракте, использованное storage и блок, на котором было сделано чтение. `finality: "final"` гарантирует, что вы читаете стабильное состояние, а не optimistic-представление. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.mainnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_account",account_id:$account_id,finality:"final"} + }')" \ + | jq '.result | {amount, locked, storage_usage, block_height, block_hash}' +``` + +Для `root.near` это возвращает `amount` (yoctoNEAR в свободной части), `locked: "0"` (ничего в валидаторском стейке или lockup-контракте) и `storage_usage: 28677` — примерно 28.7 КБ on-chain-состояния. Пара `block_height`/`block_hash` фиксирует точку чтения; чтобы прочитать несколько аккаунтов *на одном и том же* блоке, переиспользуйте возвращённый `block_hash` как `block_id` в последующих запросах. + +## Включение транзакции и финальность + +### Отследить транзакцию от хеша до финальности + +Есть tx hash? Опрашивайте `tx` с минимальным порогом `wait_until`, который отвечает на ваш вопрос. + +```bash +TX_HASH=CVyG2xLJ6fuKCtULAxMnWTh2GL5ey2UUiTcgYT3M6Pow +SIGNER_ACCOUNT_ID=mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://archival-rpc.testnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" --arg signer_id "$SIGNER_ACCOUNT_ID" '{ + jsonrpc: "2.0", id: "fastnear", method: "tx", + params: {tx_hash: $tx_hash, sender_account_id: $signer_id, wait_until: "INCLUDED"} + }')" \ + | jq '{ + asked: "INCLUDED", + final_execution_status: .result.final_execution_status, + status_class: (.result.status | keys[0]), + receipts_outcome_count: (.result.receipts_outcome | length) + }' +``` + +Для зафиксированной исторической транзакции (1-yocto self-transfer от `mike.testnet`) ответ возвращается как `FINAL`, хотя мы спрашивали `INCLUDED`. Правило такое: **`wait_until` — это минимальный порог, а не целевой**. Узел возвращает тот этап, которого транзакция действительно достигла: для исторической всегда `FINAL`; для полётной выбирайте `INCLUDED`, когда достаточно включения и нужен самый ранний возврат, или `FINAL`, когда реальный вопрос звучит «завершилась ли?». + +Два перехода отсюда: + +- **Отправляете в реальном времени?** [`broadcast_tx_async`](https://docs.fastnear.com/ru/rpc/transaction/broadcast-tx-async) возвращает хеш сразу после того, как узел принял payload — отслеживайте отдельно через `tx`. [`send_tx`](https://docs.fastnear.com/ru/rpc/transaction/send-tx) одновременно отправляет и блокируется на выбранном `wait_until` в одном запросе. +- **Нужно дерево receipts, а не только outcome?** `tx` уже включает `receipts_outcome`; расширяйте поверхность до [`EXPERIMENTAL_tx_status`](https://docs.fastnear.com/ru/rpc/transaction/experimental-tx-status) только тогда, когда дополнительно нужны сырые записи receipts. + +## Инспекция блока на tip + +### Описать первый action первой транзакции на текущем tip + +Блок NEAR — это header поверх N shard chunks, а не плоский список транзакций. `block` возвращает headers chunks; сами транзакции лежат уровнем ниже, внутри `chunk`. Шортката `block → tx` нет — блок не несёт хешей транзакций, поэтому `tx` (которому нужен hash) в этой цепочке не участвует. Канонический проход — `status` → `block` → `chunk`, пропуская пустые chunks по дороге. Большинство chunks в tip-блоке пустые — их `tx_root` равен сентинелу `11111111111111111111111111111111`, поэтому селектору нужен фильтр. + +```bash +EMPTY_TX_ROOT=11111111111111111111111111111111 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +BLOCK_HASH="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data '{"jsonrpc":"2.0","id":"fastnear","method":"status","params":[]}' \ + | jq -r '.result.sync_info.latest_block_hash')" + +CHUNK_HASH="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg block_hash "$BLOCK_HASH" '{ + jsonrpc:"2.0",id:"fastnear",method:"block",params:{block_id:$block_hash} + }')" \ + | jq -r --arg empty "$EMPTY_TX_ROOT" ' + first(.result.chunks[] | select(.tx_root != $empty) | .chunk_hash) // empty')" + +if [ -z "$CHUNK_HASH" ]; then + echo "tip block had no transactions in any chunk — rerun on the next head" +else + curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg chunk_hash "$CHUNK_HASH" '{ + jsonrpc:"2.0",id:"fastnear",method:"chunk",params:{chunk_id:$chunk_hash} + }')" \ + | jq '{ + chunk_shard: .result.header.shard_id, + chunk_height: .result.header.height_included, + first_tx: { + hash: .result.transactions[0].hash, + signer_id: .result.transactions[0].signer_id, + receiver_id: .result.transactions[0].receiver_id + }, + first_action: ( + .result.transactions[0].actions[0] as $a + | if ($a | type) == "string" then {kind: $a} + elif $a.FunctionCall then {kind: "FunctionCall", method_name: $a.FunctionCall.method_name} + else {kind: ($a | keys[0])} end + ) + }' +fi +``` + +Живой запуск возвращает первый chunk текущего tip, первую транзакцию и первый action — часто это `FunctionCall` на контракте моста или tg-бота (mainnet активен). Tip-блок может быть валидным и при этом не содержать транзакций ни в одном chunk — поэтому ветка с пустым результатом остаётся; это честный ответ для тихого момента сети. + +## Механика аккаунтов и ключей + +### Определить function-call-ключи, которые стоит удалить + +Каждый кошелёк, шлюз и dapp-сессия, в которую вы заходите, обычно оставляет за собой function-call-ключ. Большинством из них вы больше никогда не воспользуетесь. `view_access_key_list` возвращает все ключи аккаунта; структура nonce показывает, какие из них устарели. + +Новые ключи стартуют с `block_height * 10^6`, и значение инкрементируется на единицу за каждую транзакцию, которую ключ подписывает, поэтому: + +- `nonce / 10^6` → блок, в котором ключ был добавлен +- `nonce % 10^6` → сколько раз ключ был использован + +Любой ключ с `tx_count: 0` был создан и ни разу не использовался — самый очевидный кандидат на очистку. Следующий по порядку — ключи, заскоупленные на контракт, с которым вы больше не работаете. Фильтр ниже сужает до `social.near`, но чтобы аудитировать другой контракт, меняется только строка `RECEIVER_ID`. + +```bash +ACCOUNT_ID=root.near +RECEIVER_ID=social.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.mainnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_access_key_list",account_id:$account_id,finality:"final"} + }')" \ + | jq --arg receiver "$RECEIVER_ID" ' + { + total_keys: (.result.keys | length), + fcks_for_receiver: [ + .result.keys[] + | select((.access_key.permission | type) == "object") + | select(.access_key.permission.FunctionCall.receiver_id == $receiver) + | { + public_key, + added_at_block: (.access_key.nonce / 1000000 | floor), + tx_count: (.access_key.nonce % 1000000), + method_names: (.access_key.permission.FunctionCall.method_names | if . == [] then "ANY" else . end), + allowance: (.access_key.permission.FunctionCall.allowance // "unlimited") + } + ] | sort_by(.tx_count) + }' +``` + +Для `root.near` это возвращает 235 ключей всего, включая 34 function-call-ключа на `social.near`; 21 из них были созданы и ни разу не использовались (`tx_count: 0`) и потому являются прямыми кандидатами на удаление. `method_names: "ANY"` означает, что ключ может вызвать любой метод на `social.near`; сужение до списка вида `["find_grants", "insert_grant", "delete_grant"]` означает, что ключ был заскоуплен на write-поверхность одного dapp. + +Чтобы удалить такой ключ, подпишите action `DeleteKey` **full-access**-ключом (function-call-ключ не может авторизовать `DeleteKey`) и отправьте через [`send_tx`](https://docs.fastnear.com/ru/rpc/transaction/send-tx). Повторный запуск того же запроса подтвердит, что ключа больше нет. + +## Чтение контрактов и сырой state + +### Прочитать storage контракта, не запуская его + +View-метод вроде `get_num` всё равно заставляет узел загрузить wasm-контракта и выполнить его. Если ключ storage уже известен, `view_state` возвращает сырые сериализованные байты напрямую — без исполнения и без зависимости от того, выставил ли контракт getter для этого поля вообще. + +Контракты на `near-sdk-rs` хранят верхнеуровневую `#[near_bindgen]`-структуру под ключом `STATE`. Передайте `STATE` как `prefix_base64` (`U1RBVEU=` — это base64 тех же четырёх ASCII-байт), и узел вернёт сериализованное значение. + +```bash +CONTRACT_ID=counter.near-examples.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +RAW_B64="$(curl -s "https://rpc.testnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg contract "$CONTRACT_ID" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"view_state",account_id:$contract,prefix_base64:"U1RBVEU=",finality:"final"} + }')" \ + | jq -r '.result.values[0].value')" + +DECODED_I8="$(python3 -c "import base64; print(int.from_bytes(base64.b64decode('$RAW_B64'),'little',signed=True))")" + +jq -n --arg raw "$RAW_B64" --argjson val "$DECODED_I8" '{raw_bytes_base64: $raw, decoded_i8: $val}' +``` + +Для живого counter это возвращает `"CQ=="` — один байт `0x09`, декодируется как signed i8 в `9`. Это то же число, которое вернул бы `get_num`, только прочитанное прямо из trie без запуска кода контракта. `signed=True` важен: отрицательный counter сериализовался бы как `"/w=="` (байт `0xff` → i8 `-1`, а не u8 `255`). + +Тянитесь к `view_state`, когда контракт не выставляет view-метод для нужных данных или когда нужна семья ключей, которую контракт не публикует. Для большинства чтений `call_function` всё равно требует меньше церемоний. Если вопрос становится историческим, а не текущим, расширяйте поверхность до [KV FastData API](https://docs.fastnear.com/ru/fastdata/kv). + +## NEAR Social и точные чтения BOS + +Оставайтесь на точных чтениях SocialDB и on-chain-проверках готовности — пока вопрос не станет историческим. + +### Может ли этот аккаунт прямо сейчас публиковать в NEAR Social? + +`social.near` знает две вещи, о которых UI кошелька может только догадываться: сколько storage осталось у каждого аккаунта и разрешена ли делегированному signer запись под этим аккаунтом. Два view-вызова сворачивают вопрос готовности к одному boolean. + +```bash +ACCOUNT_ID=root.near # account you're writing under +SIGNER_ACCOUNT_ID=root.near # account signing the transaction +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +STORAGE_ARGS_B64="$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id:$account_id}' | base64 | tr -d '\n')" + +STORAGE="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$STORAGE_ARGS_B64" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"get_account_storage",args_base64:$args,finality:"final"} + }')" \ + | jq '.result.result | implode | fromjson')" + +if [ "$SIGNER_ACCOUNT_ID" = "$ACCOUNT_ID" ]; then + PERMISSION=true +else + PERM_ARGS_B64="$(jq -nc --arg pred "$SIGNER_ACCOUNT_ID" --arg key "$ACCOUNT_ID" '{predecessor_id:$pred,key:$key}' | base64 | tr -d '\n')" + PERMISSION="$(curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$PERM_ARGS_B64" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"is_write_permission_granted",args_base64:$args,finality:"final"} + }')" \ + | jq '.result.result | implode | fromjson')" +fi + +jq -n --argjson storage "$STORAGE" --argjson permission "$PERMISSION" \ + --arg account_id "$ACCOUNT_ID" --arg signer "$SIGNER_ACCOUNT_ID" '{ + account_id: $account_id, + signer_account_id: $signer, + storage: $storage, + permission_granted: $permission, + ready_to_publish: (($storage.available_bytes // 0) > 0 and $permission) + }' +``` + +Для `root.near`, подписывающего под собой, это возвращает `storage: {used_bytes: 136245, available_bytes: 42484}`, `permission_granted: true` (владельческая запись) и `ready_to_publish: true`. Если `storage` приходит как `null` или `available_bytes: 0`, аккаунту нужен `storage_deposit` на `social.near`, прежде чем новая запись сможет закрепиться. Если signer отличается от цели, ветка permission спрашивает `is_write_permission_granted({predecessor_id, key})` — тот же on-chain-ответ, который dapp видит, прежде чем писать от имени пользователя. Полную поверхность контракта см. в [SocialDB API](https://github.com/NearSocial/social-db#api). + +### Что `mob.near/widget/Profile` содержит прямо сейчас? + +SocialDB хранит BOS-виджеты как ключи `/widget/` на `social.near`. Один `keys` с типом возврата `BlockHeight` возвращает каталог плюс якоря последней записи по каждому виджету; один `get` возвращает точный исходник. + +```bash +ACCOUNT_ID=mob.near +WIDGET_NAME=Profile +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +KEYS_ARGS="$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + keys: [($account_id + "/widget/*")], + options: {return_type: "BlockHeight"} +}' | base64 | tr -d '\n')" + +curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$KEYS_ARGS" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"keys",args_base64:$args,finality:"final"} + }')" \ + | jq --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" ' + .result.result | implode | fromjson | .[$account_id].widget as $map + | { + total_widgets: ($map | length), + most_recently_written: ($map | to_entries | sort_by(-.value) | .[0:5] | map({widget: .key, last_write_block: .value})), + target_last_write_block: $map[$widget] + }' + +GET_ARGS="$(jq -nc --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" '{ + keys: [($account_id + "/widget/" + $widget)] +}' | base64 | tr -d '\n')" + +curl -s "https://rpc.mainnet.fastnear.com" "${AUTH_HEADER[@]}" -H 'content-type: application/json' \ + --data "$(jq -nc --arg args "$GET_ARGS" '{ + jsonrpc:"2.0",id:"fastnear",method:"query", + params:{request_type:"call_function",account_id:"social.near",method_name:"get",args_base64:$args,finality:"final"} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" --arg widget "$WIDGET_NAME" ' + .result.result | implode | fromjson | .[$account_id].widget[$widget] | split("\n")[0:20] | join("\n")' +``` + +Для `mob.near` каталог показывает 264 виджета; `Profile` последний раз записывался в блоке `86494825` — годами ранее, стабильно с тех пор — и исходник начинается с `const accountId = props.accountId ?? context.accountId;`. Тип возврата `BlockHeight` ничего не стоит дополнительно и превращает листинг ключей в дешёвую проверку актуальности. Сохраните блок последней записи, если позже захотите доказать, *какая транзакция* записала именно эту версию — передайте его в [Расширенный поиск записи SocialDB](https://docs.fastnear.com/ru/tx/socialdb-proofs). + +## Частые ошибки + +- Начинать в RPC, когда пользователю нужна сводка по активам или индексированная история. +- Забывать переключаться с обычного RPC на archival RPC для более старого state. +- Считать browser auth в UI документации продовым backend-паттерном. +- Оставаться в низкоуровневых вызовах статуса транзакции, когда вопрос уже стал forensic или историческим. + +## Связанные страницы + +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [Auth & Access](https://docs.fastnear.com/ru/auth) +- [FastNear API](https://docs.fastnear.com/ru/api) +- [Transactions API](https://docs.fastnear.com/ru/tx) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/index.md b/static/ru/rpc/index.md index 6bd09fc..7e0b256 100644 --- a/static/ru/rpc/index.md +++ b/static/ru/rpc/index.md @@ -35,6 +35,10 @@ https://archival-rpc.testnet.fastnear.com - [`send_tx`](https://docs.fastnear.com/ru/rpc/transaction/send-tx) — отправка транзакций; [`tx`](https://docs.fastnear.com/ru/rpc/transaction/tx-status) — статус исполнения. - [`validators`](https://docs.fastnear.com/ru/rpc/validators/validators-current) — валидаторы текущей эпохи. +## Нужен сценарий? + +Используйте [примеры RPC](https://docs.fastnear.com/ru/rpc/examples) для практических примеров: точных проверок состояния, анализа блоков, view-вызовов контрактов и отправки транзакций с подтверждением. + ## Используйте RPC, когда - нужны канонические формы запросов и ответов из протокола; @@ -76,3 +80,10 @@ https://archival-rpc.testnet.fastnear.com ### Мне нужен более простой ответ, чем даёт JSON-RPC Обычно это означает, что нужно индексированное REST-семейство, а не сырой RPC. Воспользуйтесь страницей выбора поверхности и подберите более высокий уровень абстракции. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/changes.md b/static/ru/rpc/protocol/changes.md index ae95691..cd399f9 100644 --- a/static/ru/rpc/protocol/changes.md +++ b/static/ru/rpc/protocol/changes.md @@ -222,3 +222,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/changes/index.md b/static/ru/rpc/protocol/changes/index.md index ae95691..cd399f9 100644 --- a/static/ru/rpc/protocol/changes/index.md +++ b/static/ru/rpc/protocol/changes/index.md @@ -222,3 +222,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/chunk-by-block-shard.md b/static/ru/rpc/protocol/chunk-by-block-shard.md index 36f3242..c8cc9b2 100644 --- a/static/ru/rpc/protocol/chunk-by-block-shard.md +++ b/static/ru/rpc/protocol/chunk-by-block-shard.md @@ -442,3 +442,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/chunk-by-block-shard/index.md b/static/ru/rpc/protocol/chunk-by-block-shard/index.md index 36f3242..c8cc9b2 100644 --- a/static/ru/rpc/protocol/chunk-by-block-shard/index.md +++ b/static/ru/rpc/protocol/chunk-by-block-shard/index.md @@ -442,3 +442,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/chunk-by-hash.md b/static/ru/rpc/protocol/chunk-by-hash.md index 62c5b03..b3a5656 100644 --- a/static/ru/rpc/protocol/chunk-by-hash.md +++ b/static/ru/rpc/protocol/chunk-by-hash.md @@ -421,3 +421,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/chunk-by-hash/index.md b/static/ru/rpc/protocol/chunk-by-hash/index.md index 62c5b03..b3a5656 100644 --- a/static/ru/rpc/protocol/chunk-by-hash/index.md +++ b/static/ru/rpc/protocol/chunk-by-hash/index.md @@ -421,3 +421,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/client-config.md b/static/ru/rpc/protocol/client-config.md index 3973433..954932b 100644 --- a/static/ru/rpc/protocol/client-config.md +++ b/static/ru/rpc/protocol/client-config.md @@ -1028,3 +1028,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/client-config/index.md b/static/ru/rpc/protocol/client-config/index.md index 3973433..954932b 100644 --- a/static/ru/rpc/protocol/client-config/index.md +++ b/static/ru/rpc/protocol/client-config/index.md @@ -1028,3 +1028,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/experimental-congestion-level.md b/static/ru/rpc/protocol/experimental-congestion-level.md index 38442dd..1c81283 100644 --- a/static/ru/rpc/protocol/experimental-congestion-level.md +++ b/static/ru/rpc/protocol/experimental-congestion-level.md @@ -226,3 +226,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/experimental-congestion-level/index.md b/static/ru/rpc/protocol/experimental-congestion-level/index.md index 38442dd..1c81283 100644 --- a/static/ru/rpc/protocol/experimental-congestion-level/index.md +++ b/static/ru/rpc/protocol/experimental-congestion-level/index.md @@ -226,3 +226,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/experimental-light-client-block-proof.md b/static/ru/rpc/protocol/experimental-light-client-block-proof.md index 9d6159c..dca694c 100644 --- a/static/ru/rpc/protocol/experimental-light-client-block-proof.md +++ b/static/ru/rpc/protocol/experimental-light-client-block-proof.md @@ -257,3 +257,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/experimental-light-client-block-proof/index.md b/static/ru/rpc/protocol/experimental-light-client-block-proof/index.md index 9d6159c..dca694c 100644 --- a/static/ru/rpc/protocol/experimental-light-client-block-proof/index.md +++ b/static/ru/rpc/protocol/experimental-light-client-block-proof/index.md @@ -257,3 +257,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/experimental-light-client-proof.md b/static/ru/rpc/protocol/experimental-light-client-proof.md index 43e4556..4c255de 100644 --- a/static/ru/rpc/protocol/experimental-light-client-proof.md +++ b/static/ru/rpc/protocol/experimental-light-client-proof.md @@ -359,3 +359,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/experimental-light-client-proof/index.md b/static/ru/rpc/protocol/experimental-light-client-proof/index.md index 43e4556..4c255de 100644 --- a/static/ru/rpc/protocol/experimental-light-client-proof/index.md +++ b/static/ru/rpc/protocol/experimental-light-client-proof/index.md @@ -359,3 +359,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/experimental-protocol-config.md b/static/ru/rpc/protocol/experimental-protocol-config.md index 5436e52..843ddae 100644 --- a/static/ru/rpc/protocol/experimental-protocol-config.md +++ b/static/ru/rpc/protocol/experimental-protocol-config.md @@ -543,3 +543,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/experimental-protocol-config/index.md b/static/ru/rpc/protocol/experimental-protocol-config/index.md index 5436e52..843ddae 100644 --- a/static/ru/rpc/protocol/experimental-protocol-config/index.md +++ b/static/ru/rpc/protocol/experimental-protocol-config/index.md @@ -543,3 +543,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/experimental-split-storage-info.md b/static/ru/rpc/protocol/experimental-split-storage-info.md index 20da6d8..316d9f5 100644 --- a/static/ru/rpc/protocol/experimental-split-storage-info.md +++ b/static/ru/rpc/protocol/experimental-split-storage-info.md @@ -212,3 +212,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/experimental-split-storage-info/index.md b/static/ru/rpc/protocol/experimental-split-storage-info/index.md index 20da6d8..316d9f5 100644 --- a/static/ru/rpc/protocol/experimental-split-storage-info/index.md +++ b/static/ru/rpc/protocol/experimental-split-storage-info/index.md @@ -212,3 +212,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/gas-price-by-block.md b/static/ru/rpc/protocol/gas-price-by-block.md index f428b09..4e52f8d 100644 --- a/static/ru/rpc/protocol/gas-price-by-block.md +++ b/static/ru/rpc/protocol/gas-price-by-block.md @@ -213,3 +213,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/gas-price-by-block/index.md b/static/ru/rpc/protocol/gas-price-by-block/index.md index f428b09..4e52f8d 100644 --- a/static/ru/rpc/protocol/gas-price-by-block/index.md +++ b/static/ru/rpc/protocol/gas-price-by-block/index.md @@ -213,3 +213,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/gas-price.md b/static/ru/rpc/protocol/gas-price.md index cac921d..756ac4f 100644 --- a/static/ru/rpc/protocol/gas-price.md +++ b/static/ru/rpc/protocol/gas-price.md @@ -195,3 +195,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/gas-price/index.md b/static/ru/rpc/protocol/gas-price/index.md index cac921d..756ac4f 100644 --- a/static/ru/rpc/protocol/gas-price/index.md +++ b/static/ru/rpc/protocol/gas-price/index.md @@ -195,3 +195,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/genesis-config.md b/static/ru/rpc/protocol/genesis-config.md index 752af01..a65474c 100644 --- a/static/ru/rpc/protocol/genesis-config.md +++ b/static/ru/rpc/protocol/genesis-config.md @@ -596,3 +596,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/genesis-config/index.md b/static/ru/rpc/protocol/genesis-config/index.md index 752af01..a65474c 100644 --- a/static/ru/rpc/protocol/genesis-config/index.md +++ b/static/ru/rpc/protocol/genesis-config/index.md @@ -596,3 +596,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/health.md b/static/ru/rpc/protocol/health.md index 35ea5a5..4d137b6 100644 --- a/static/ru/rpc/protocol/health.md +++ b/static/ru/rpc/protocol/health.md @@ -175,3 +175,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/health/index.md b/static/ru/rpc/protocol/health/index.md index 35ea5a5..4d137b6 100644 --- a/static/ru/rpc/protocol/health/index.md +++ b/static/ru/rpc/protocol/health/index.md @@ -175,3 +175,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/latest-block.md b/static/ru/rpc/protocol/latest-block.md index 240ce98..ab28723 100644 --- a/static/ru/rpc/protocol/latest-block.md +++ b/static/ru/rpc/protocol/latest-block.md @@ -196,3 +196,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/latest-block/index.md b/static/ru/rpc/protocol/latest-block/index.md index 240ce98..ab28723 100644 --- a/static/ru/rpc/protocol/latest-block/index.md +++ b/static/ru/rpc/protocol/latest-block/index.md @@ -196,3 +196,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/light-client-proof.md b/static/ru/rpc/protocol/light-client-proof.md index f7b54a4..5d9e849 100644 --- a/static/ru/rpc/protocol/light-client-proof.md +++ b/static/ru/rpc/protocol/light-client-proof.md @@ -359,3 +359,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/light-client-proof/index.md b/static/ru/rpc/protocol/light-client-proof/index.md index f7b54a4..5d9e849 100644 --- a/static/ru/rpc/protocol/light-client-proof/index.md +++ b/static/ru/rpc/protocol/light-client-proof/index.md @@ -359,3 +359,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/maintenance-windows.md b/static/ru/rpc/protocol/maintenance-windows.md index 695dbca..eac058a 100644 --- a/static/ru/rpc/protocol/maintenance-windows.md +++ b/static/ru/rpc/protocol/maintenance-windows.md @@ -216,3 +216,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/maintenance-windows/index.md b/static/ru/rpc/protocol/maintenance-windows/index.md index 695dbca..eac058a 100644 --- a/static/ru/rpc/protocol/maintenance-windows/index.md +++ b/static/ru/rpc/protocol/maintenance-windows/index.md @@ -216,3 +216,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/metrics.md b/static/ru/rpc/protocol/metrics.md index 4f910f2..f96f4fd 100644 --- a/static/ru/rpc/protocol/metrics.md +++ b/static/ru/rpc/protocol/metrics.md @@ -43,3 +43,10 @@ "example": "# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.\n# TYPE process_cpu_seconds_total counter\nprocess_cpu_seconds_total 12.34" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/metrics/index.md b/static/ru/rpc/protocol/metrics/index.md index 4f910f2..f96f4fd 100644 --- a/static/ru/rpc/protocol/metrics/index.md +++ b/static/ru/rpc/protocol/metrics/index.md @@ -43,3 +43,10 @@ "example": "# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.\n# TYPE process_cpu_seconds_total counter\nprocess_cpu_seconds_total 12.34" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/network-info.md b/static/ru/rpc/protocol/network-info.md index 0a1182f..a67a2dc 100644 --- a/static/ru/rpc/protocol/network-info.md +++ b/static/ru/rpc/protocol/network-info.md @@ -237,3 +237,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/network-info/index.md b/static/ru/rpc/protocol/network-info/index.md index 0a1182f..a67a2dc 100644 --- a/static/ru/rpc/protocol/network-info/index.md +++ b/static/ru/rpc/protocol/network-info/index.md @@ -237,3 +237,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/next-light-client-block.md b/static/ru/rpc/protocol/next-light-client-block.md index 549da18..3db9d79 100644 --- a/static/ru/rpc/protocol/next-light-client-block.md +++ b/static/ru/rpc/protocol/next-light-client-block.md @@ -334,3 +334,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/next-light-client-block/index.md b/static/ru/rpc/protocol/next-light-client-block/index.md index 549da18..3db9d79 100644 --- a/static/ru/rpc/protocol/next-light-client-block/index.md +++ b/static/ru/rpc/protocol/next-light-client-block/index.md @@ -334,3 +334,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/status.md b/static/ru/rpc/protocol/status.md index e25b0f9..5c3ec62 100644 --- a/static/ru/rpc/protocol/status.md +++ b/static/ru/rpc/protocol/status.md @@ -494,3 +494,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/protocol/status/index.md b/static/ru/rpc/protocol/status/index.md index e25b0f9..5c3ec62 100644 --- a/static/ru/rpc/protocol/status/index.md +++ b/static/ru/rpc/protocol/status/index.md @@ -494,3 +494,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/transaction/broadcast-tx-async.md b/static/ru/rpc/transaction/broadcast-tx-async.md index ed31a36..538b209 100644 --- a/static/ru/rpc/transaction/broadcast-tx-async.md +++ b/static/ru/rpc/transaction/broadcast-tx-async.md @@ -210,3 +210,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/transaction/broadcast-tx-async/index.md b/static/ru/rpc/transaction/broadcast-tx-async/index.md index ed31a36..538b209 100644 --- a/static/ru/rpc/transaction/broadcast-tx-async/index.md +++ b/static/ru/rpc/transaction/broadcast-tx-async/index.md @@ -210,3 +210,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/transaction/broadcast-tx-commit.md b/static/ru/rpc/transaction/broadcast-tx-commit.md index a3dade9..64bf9cc 100644 --- a/static/ru/rpc/transaction/broadcast-tx-commit.md +++ b/static/ru/rpc/transaction/broadcast-tx-commit.md @@ -276,3 +276,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/transaction/broadcast-tx-commit/index.md b/static/ru/rpc/transaction/broadcast-tx-commit/index.md index a3dade9..64bf9cc 100644 --- a/static/ru/rpc/transaction/broadcast-tx-commit/index.md +++ b/static/ru/rpc/transaction/broadcast-tx-commit/index.md @@ -276,3 +276,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/transaction/experimental-receipt.md b/static/ru/rpc/transaction/experimental-receipt.md index ebbe988..532666b 100644 --- a/static/ru/rpc/transaction/experimental-receipt.md +++ b/static/ru/rpc/transaction/experimental-receipt.md @@ -241,3 +241,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/transaction/experimental-receipt/index.md b/static/ru/rpc/transaction/experimental-receipt/index.md index ebbe988..532666b 100644 --- a/static/ru/rpc/transaction/experimental-receipt/index.md +++ b/static/ru/rpc/transaction/experimental-receipt/index.md @@ -241,3 +241,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/transaction/experimental-tx-status.md b/static/ru/rpc/transaction/experimental-tx-status.md index b2bf419..a763990 100644 --- a/static/ru/rpc/transaction/experimental-tx-status.md +++ b/static/ru/rpc/transaction/experimental-tx-status.md @@ -295,3 +295,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/transaction/experimental-tx-status/index.md b/static/ru/rpc/transaction/experimental-tx-status/index.md index b2bf419..a763990 100644 --- a/static/ru/rpc/transaction/experimental-tx-status/index.md +++ b/static/ru/rpc/transaction/experimental-tx-status/index.md @@ -295,3 +295,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/transaction/send-tx.md b/static/ru/rpc/transaction/send-tx.md index 190c819..ff314e1 100644 --- a/static/ru/rpc/transaction/send-tx.md +++ b/static/ru/rpc/transaction/send-tx.md @@ -278,3 +278,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/transaction/send-tx/index.md b/static/ru/rpc/transaction/send-tx/index.md index 190c819..ff314e1 100644 --- a/static/ru/rpc/transaction/send-tx/index.md +++ b/static/ru/rpc/transaction/send-tx/index.md @@ -278,3 +278,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/transaction/tx-status.md b/static/ru/rpc/transaction/tx-status.md index 42b7be5..556bbb6 100644 --- a/static/ru/rpc/transaction/tx-status.md +++ b/static/ru/rpc/transaction/tx-status.md @@ -293,3 +293,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/transaction/tx-status/index.md b/static/ru/rpc/transaction/tx-status/index.md index 42b7be5..556bbb6 100644 --- a/static/ru/rpc/transaction/tx-status/index.md +++ b/static/ru/rpc/transaction/tx-status/index.md @@ -293,3 +293,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/validators/experimental-validators-ordered.md b/static/ru/rpc/validators/experimental-validators-ordered.md index 861c031..dbb0e1d 100644 --- a/static/ru/rpc/validators/experimental-validators-ordered.md +++ b/static/ru/rpc/validators/experimental-validators-ordered.md @@ -204,3 +204,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/validators/experimental-validators-ordered/index.md b/static/ru/rpc/validators/experimental-validators-ordered/index.md index 861c031..dbb0e1d 100644 --- a/static/ru/rpc/validators/experimental-validators-ordered/index.md +++ b/static/ru/rpc/validators/experimental-validators-ordered/index.md @@ -204,3 +204,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/validators/validators-by-epoch.md b/static/ru/rpc/validators/validators-by-epoch.md index 095c8dd..307708f 100644 --- a/static/ru/rpc/validators/validators-by-epoch.md +++ b/static/ru/rpc/validators/validators-by-epoch.md @@ -292,3 +292,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/validators/validators-by-epoch/index.md b/static/ru/rpc/validators/validators-by-epoch/index.md index 095c8dd..307708f 100644 --- a/static/ru/rpc/validators/validators-by-epoch/index.md +++ b/static/ru/rpc/validators/validators-by-epoch/index.md @@ -292,3 +292,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/validators/validators-current.md b/static/ru/rpc/validators/validators-current.md index 37bbde5..dbfb5d9 100644 --- a/static/ru/rpc/validators/validators-current.md +++ b/static/ru/rpc/validators/validators-current.md @@ -283,3 +283,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpc/validators/validators-current/index.md b/static/ru/rpc/validators/validators-current/index.md index 37bbde5..dbfb5d9 100644 --- a/static/ru/rpc/validators/validators-current/index.md +++ b/static/ru/rpc/validators/validators-current/index.md @@ -283,3 +283,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/account/view_access_key.md b/static/ru/rpcs/account/view_access_key.md index a13d86e..2b49490 100644 --- a/static/ru/rpcs/account/view_access_key.md +++ b/static/ru/rpcs/account/view_access_key.md @@ -254,3 +254,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/account/view_access_key/index.md b/static/ru/rpcs/account/view_access_key/index.md index a13d86e..2b49490 100644 --- a/static/ru/rpcs/account/view_access_key/index.md +++ b/static/ru/rpcs/account/view_access_key/index.md @@ -254,3 +254,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/account/view_access_key_list.md b/static/ru/rpcs/account/view_access_key_list.md index 824a410..1557ba7 100644 --- a/static/ru/rpcs/account/view_access_key_list.md +++ b/static/ru/rpcs/account/view_access_key_list.md @@ -236,3 +236,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/account/view_access_key_list/index.md b/static/ru/rpcs/account/view_access_key_list/index.md index 824a410..1557ba7 100644 --- a/static/ru/rpcs/account/view_access_key_list/index.md +++ b/static/ru/rpcs/account/view_access_key_list/index.md @@ -236,3 +236,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/account/view_account.md b/static/ru/rpcs/account/view_account.md index 5219e10..8c904c0 100644 --- a/static/ru/rpcs/account/view_account.md +++ b/static/ru/rpcs/account/view_account.md @@ -288,3 +288,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/account/view_account/index.md b/static/ru/rpcs/account/view_account/index.md index 5219e10..8c904c0 100644 --- a/static/ru/rpcs/account/view_account/index.md +++ b/static/ru/rpcs/account/view_account/index.md @@ -288,3 +288,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/block/block_by_height.md b/static/ru/rpcs/block/block_by_height.md index 851677e..a84711b 100644 --- a/static/ru/rpcs/block/block_by_height.md +++ b/static/ru/rpcs/block/block_by_height.md @@ -190,3 +190,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/block/block_by_height/index.md b/static/ru/rpcs/block/block_by_height/index.md index 851677e..a84711b 100644 --- a/static/ru/rpcs/block/block_by_height/index.md +++ b/static/ru/rpcs/block/block_by_height/index.md @@ -190,3 +190,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/block/block_by_id.md b/static/ru/rpcs/block/block_by_id.md index 752e98b..0c9a325 100644 --- a/static/ru/rpcs/block/block_by_id.md +++ b/static/ru/rpcs/block/block_by_id.md @@ -190,3 +190,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/block/block_by_id/index.md b/static/ru/rpcs/block/block_by_id/index.md index 752e98b..0c9a325 100644 --- a/static/ru/rpcs/block/block_by_id/index.md +++ b/static/ru/rpcs/block/block_by_id/index.md @@ -190,3 +190,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/block/block_effects.md b/static/ru/rpcs/block/block_effects.md index b42d69e..4523c67 100644 --- a/static/ru/rpcs/block/block_effects.md +++ b/static/ru/rpcs/block/block_effects.md @@ -224,3 +224,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/block/block_effects/index.md b/static/ru/rpcs/block/block_effects/index.md index b42d69e..4523c67 100644 --- a/static/ru/rpcs/block/block_effects/index.md +++ b/static/ru/rpcs/block/block_effects/index.md @@ -224,3 +224,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/contract/call.md b/static/ru/rpcs/contract/call.md index f350ca1..999959e 100644 --- a/static/ru/rpcs/contract/call.md +++ b/static/ru/rpcs/contract/call.md @@ -271,3 +271,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/contract/call/index.md b/static/ru/rpcs/contract/call/index.md index f350ca1..999959e 100644 --- a/static/ru/rpcs/contract/call/index.md +++ b/static/ru/rpcs/contract/call/index.md @@ -271,3 +271,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/contract/view_code.md b/static/ru/rpcs/contract/view_code.md index 705c4ad..9ef3277 100644 --- a/static/ru/rpcs/contract/view_code.md +++ b/static/ru/rpcs/contract/view_code.md @@ -241,3 +241,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/contract/view_code/index.md b/static/ru/rpcs/contract/view_code/index.md index 705c4ad..9ef3277 100644 --- a/static/ru/rpcs/contract/view_code/index.md +++ b/static/ru/rpcs/contract/view_code/index.md @@ -241,3 +241,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/contract/view_global_contract_code.md b/static/ru/rpcs/contract/view_global_contract_code.md index 7b0835b..036080e 100644 --- a/static/ru/rpcs/contract/view_global_contract_code.md +++ b/static/ru/rpcs/contract/view_global_contract_code.md @@ -241,3 +241,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/contract/view_global_contract_code/index.md b/static/ru/rpcs/contract/view_global_contract_code/index.md index 7b0835b..036080e 100644 --- a/static/ru/rpcs/contract/view_global_contract_code/index.md +++ b/static/ru/rpcs/contract/view_global_contract_code/index.md @@ -241,3 +241,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/contract/view_global_contract_code_by_account_id.md b/static/ru/rpcs/contract/view_global_contract_code_by_account_id.md index 79c99c8..e3b7ce3 100644 --- a/static/ru/rpcs/contract/view_global_contract_code_by_account_id.md +++ b/static/ru/rpcs/contract/view_global_contract_code_by_account_id.md @@ -241,3 +241,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/contract/view_global_contract_code_by_account_id/index.md b/static/ru/rpcs/contract/view_global_contract_code_by_account_id/index.md index 79c99c8..e3b7ce3 100644 --- a/static/ru/rpcs/contract/view_global_contract_code_by_account_id/index.md +++ b/static/ru/rpcs/contract/view_global_contract_code_by_account_id/index.md @@ -241,3 +241,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/contract/view_state.md b/static/ru/rpcs/contract/view_state.md index e816aec..e2fbf29 100644 --- a/static/ru/rpcs/contract/view_state.md +++ b/static/ru/rpcs/contract/view_state.md @@ -267,3 +267,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/contract/view_state/index.md b/static/ru/rpcs/contract/view_state/index.md index e816aec..e2fbf29 100644 --- a/static/ru/rpcs/contract/view_state/index.md +++ b/static/ru/rpcs/contract/view_state/index.md @@ -267,3 +267,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/EXPERIMENTAL_congestion_level.md b/static/ru/rpcs/protocol/EXPERIMENTAL_congestion_level.md index 7439c23..d609f19 100644 --- a/static/ru/rpcs/protocol/EXPERIMENTAL_congestion_level.md +++ b/static/ru/rpcs/protocol/EXPERIMENTAL_congestion_level.md @@ -225,3 +225,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/EXPERIMENTAL_congestion_level/index.md b/static/ru/rpcs/protocol/EXPERIMENTAL_congestion_level/index.md index 7439c23..d609f19 100644 --- a/static/ru/rpcs/protocol/EXPERIMENTAL_congestion_level/index.md +++ b/static/ru/rpcs/protocol/EXPERIMENTAL_congestion_level/index.md @@ -225,3 +225,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_block_proof.md b/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_block_proof.md index b659e04..7d6d1d6 100644 --- a/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_block_proof.md +++ b/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_block_proof.md @@ -256,3 +256,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_block_proof/index.md b/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_block_proof/index.md index b659e04..7d6d1d6 100644 --- a/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_block_proof/index.md +++ b/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_block_proof/index.md @@ -256,3 +256,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_proof.md b/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_proof.md index a15dc8c..8e89e6c 100644 --- a/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_proof.md +++ b/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_proof.md @@ -358,3 +358,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_proof/index.md b/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_proof/index.md index a15dc8c..8e89e6c 100644 --- a/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_proof/index.md +++ b/static/ru/rpcs/protocol/EXPERIMENTAL_light_client_proof/index.md @@ -358,3 +358,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/EXPERIMENTAL_protocol_config.md b/static/ru/rpcs/protocol/EXPERIMENTAL_protocol_config.md index eafdcd0..f94c243 100644 --- a/static/ru/rpcs/protocol/EXPERIMENTAL_protocol_config.md +++ b/static/ru/rpcs/protocol/EXPERIMENTAL_protocol_config.md @@ -542,3 +542,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/EXPERIMENTAL_protocol_config/index.md b/static/ru/rpcs/protocol/EXPERIMENTAL_protocol_config/index.md index eafdcd0..f94c243 100644 --- a/static/ru/rpcs/protocol/EXPERIMENTAL_protocol_config/index.md +++ b/static/ru/rpcs/protocol/EXPERIMENTAL_protocol_config/index.md @@ -542,3 +542,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/EXPERIMENTAL_split_storage_info.md b/static/ru/rpcs/protocol/EXPERIMENTAL_split_storage_info.md index 0078b86..d09ef9e 100644 --- a/static/ru/rpcs/protocol/EXPERIMENTAL_split_storage_info.md +++ b/static/ru/rpcs/protocol/EXPERIMENTAL_split_storage_info.md @@ -211,3 +211,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/EXPERIMENTAL_split_storage_info/index.md b/static/ru/rpcs/protocol/EXPERIMENTAL_split_storage_info/index.md index 0078b86..d09ef9e 100644 --- a/static/ru/rpcs/protocol/EXPERIMENTAL_split_storage_info/index.md +++ b/static/ru/rpcs/protocol/EXPERIMENTAL_split_storage_info/index.md @@ -211,3 +211,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/changes.md b/static/ru/rpcs/protocol/changes.md index 1f84715..bd8714e 100644 --- a/static/ru/rpcs/protocol/changes.md +++ b/static/ru/rpcs/protocol/changes.md @@ -221,3 +221,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/changes/index.md b/static/ru/rpcs/protocol/changes/index.md index 1f84715..bd8714e 100644 --- a/static/ru/rpcs/protocol/changes/index.md +++ b/static/ru/rpcs/protocol/changes/index.md @@ -221,3 +221,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/chunk_by_block_shard.md b/static/ru/rpcs/protocol/chunk_by_block_shard.md index bfbab60..21c03f5 100644 --- a/static/ru/rpcs/protocol/chunk_by_block_shard.md +++ b/static/ru/rpcs/protocol/chunk_by_block_shard.md @@ -441,3 +441,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/chunk_by_block_shard/index.md b/static/ru/rpcs/protocol/chunk_by_block_shard/index.md index bfbab60..21c03f5 100644 --- a/static/ru/rpcs/protocol/chunk_by_block_shard/index.md +++ b/static/ru/rpcs/protocol/chunk_by_block_shard/index.md @@ -441,3 +441,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/chunk_by_hash.md b/static/ru/rpcs/protocol/chunk_by_hash.md index ae2ff4b..43dd6a1 100644 --- a/static/ru/rpcs/protocol/chunk_by_hash.md +++ b/static/ru/rpcs/protocol/chunk_by_hash.md @@ -420,3 +420,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/chunk_by_hash/index.md b/static/ru/rpcs/protocol/chunk_by_hash/index.md index ae2ff4b..43dd6a1 100644 --- a/static/ru/rpcs/protocol/chunk_by_hash/index.md +++ b/static/ru/rpcs/protocol/chunk_by_hash/index.md @@ -420,3 +420,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/client_config.md b/static/ru/rpcs/protocol/client_config.md index 88030bc..4e8c672 100644 --- a/static/ru/rpcs/protocol/client_config.md +++ b/static/ru/rpcs/protocol/client_config.md @@ -1027,3 +1027,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/client_config/index.md b/static/ru/rpcs/protocol/client_config/index.md index 88030bc..4e8c672 100644 --- a/static/ru/rpcs/protocol/client_config/index.md +++ b/static/ru/rpcs/protocol/client_config/index.md @@ -1027,3 +1027,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/gas_price.md b/static/ru/rpcs/protocol/gas_price.md index 0f7d36d..24da275 100644 --- a/static/ru/rpcs/protocol/gas_price.md +++ b/static/ru/rpcs/protocol/gas_price.md @@ -194,3 +194,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/gas_price/index.md b/static/ru/rpcs/protocol/gas_price/index.md index 0f7d36d..24da275 100644 --- a/static/ru/rpcs/protocol/gas_price/index.md +++ b/static/ru/rpcs/protocol/gas_price/index.md @@ -194,3 +194,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/gas_price_by_block.md b/static/ru/rpcs/protocol/gas_price_by_block.md index 0b8c8be..6660fe8 100644 --- a/static/ru/rpcs/protocol/gas_price_by_block.md +++ b/static/ru/rpcs/protocol/gas_price_by_block.md @@ -212,3 +212,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/gas_price_by_block/index.md b/static/ru/rpcs/protocol/gas_price_by_block/index.md index 0b8c8be..6660fe8 100644 --- a/static/ru/rpcs/protocol/gas_price_by_block/index.md +++ b/static/ru/rpcs/protocol/gas_price_by_block/index.md @@ -212,3 +212,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/genesis_config.md b/static/ru/rpcs/protocol/genesis_config.md index 3808ffe..99b7913 100644 --- a/static/ru/rpcs/protocol/genesis_config.md +++ b/static/ru/rpcs/protocol/genesis_config.md @@ -595,3 +595,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/genesis_config/index.md b/static/ru/rpcs/protocol/genesis_config/index.md index 3808ffe..99b7913 100644 --- a/static/ru/rpcs/protocol/genesis_config/index.md +++ b/static/ru/rpcs/protocol/genesis_config/index.md @@ -595,3 +595,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/health.md b/static/ru/rpcs/protocol/health.md index 073c6cb..c56987d 100644 --- a/static/ru/rpcs/protocol/health.md +++ b/static/ru/rpcs/protocol/health.md @@ -174,3 +174,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/health/index.md b/static/ru/rpcs/protocol/health/index.md index 073c6cb..c56987d 100644 --- a/static/ru/rpcs/protocol/health/index.md +++ b/static/ru/rpcs/protocol/health/index.md @@ -174,3 +174,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/latest_block.md b/static/ru/rpcs/protocol/latest_block.md index cbc9225..666f63b 100644 --- a/static/ru/rpcs/protocol/latest_block.md +++ b/static/ru/rpcs/protocol/latest_block.md @@ -195,3 +195,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/latest_block/index.md b/static/ru/rpcs/protocol/latest_block/index.md index cbc9225..666f63b 100644 --- a/static/ru/rpcs/protocol/latest_block/index.md +++ b/static/ru/rpcs/protocol/latest_block/index.md @@ -195,3 +195,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/light_client_proof.md b/static/ru/rpcs/protocol/light_client_proof.md index b3335b1..36ab61d 100644 --- a/static/ru/rpcs/protocol/light_client_proof.md +++ b/static/ru/rpcs/protocol/light_client_proof.md @@ -358,3 +358,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/light_client_proof/index.md b/static/ru/rpcs/protocol/light_client_proof/index.md index b3335b1..36ab61d 100644 --- a/static/ru/rpcs/protocol/light_client_proof/index.md +++ b/static/ru/rpcs/protocol/light_client_proof/index.md @@ -358,3 +358,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/maintenance_windows.md b/static/ru/rpcs/protocol/maintenance_windows.md index 744ef7f..ecb329a 100644 --- a/static/ru/rpcs/protocol/maintenance_windows.md +++ b/static/ru/rpcs/protocol/maintenance_windows.md @@ -215,3 +215,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/maintenance_windows/index.md b/static/ru/rpcs/protocol/maintenance_windows/index.md index 744ef7f..ecb329a 100644 --- a/static/ru/rpcs/protocol/maintenance_windows/index.md +++ b/static/ru/rpcs/protocol/maintenance_windows/index.md @@ -215,3 +215,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/metrics.md b/static/ru/rpcs/protocol/metrics.md index 98ea8e9..1bc7a15 100644 --- a/static/ru/rpcs/protocol/metrics.md +++ b/static/ru/rpcs/protocol/metrics.md @@ -42,3 +42,10 @@ "example": "# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.\n# TYPE process_cpu_seconds_total counter\nprocess_cpu_seconds_total 12.34" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/metrics/index.md b/static/ru/rpcs/protocol/metrics/index.md index 98ea8e9..1bc7a15 100644 --- a/static/ru/rpcs/protocol/metrics/index.md +++ b/static/ru/rpcs/protocol/metrics/index.md @@ -42,3 +42,10 @@ "example": "# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.\n# TYPE process_cpu_seconds_total counter\nprocess_cpu_seconds_total 12.34" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/network_info.md b/static/ru/rpcs/protocol/network_info.md index a6562f1..050b3f0 100644 --- a/static/ru/rpcs/protocol/network_info.md +++ b/static/ru/rpcs/protocol/network_info.md @@ -236,3 +236,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/network_info/index.md b/static/ru/rpcs/protocol/network_info/index.md index a6562f1..050b3f0 100644 --- a/static/ru/rpcs/protocol/network_info/index.md +++ b/static/ru/rpcs/protocol/network_info/index.md @@ -236,3 +236,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/next_light_client_block.md b/static/ru/rpcs/protocol/next_light_client_block.md index 22f2f14..33569a0 100644 --- a/static/ru/rpcs/protocol/next_light_client_block.md +++ b/static/ru/rpcs/protocol/next_light_client_block.md @@ -333,3 +333,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/next_light_client_block/index.md b/static/ru/rpcs/protocol/next_light_client_block/index.md index 22f2f14..33569a0 100644 --- a/static/ru/rpcs/protocol/next_light_client_block/index.md +++ b/static/ru/rpcs/protocol/next_light_client_block/index.md @@ -333,3 +333,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/status.md b/static/ru/rpcs/protocol/status.md index e660141..cb3fb90 100644 --- a/static/ru/rpcs/protocol/status.md +++ b/static/ru/rpcs/protocol/status.md @@ -493,3 +493,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/protocol/status/index.md b/static/ru/rpcs/protocol/status/index.md index e660141..cb3fb90 100644 --- a/static/ru/rpcs/protocol/status/index.md +++ b/static/ru/rpcs/protocol/status/index.md @@ -493,3 +493,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/transaction/EXPERIMENTAL_receipt.md b/static/ru/rpcs/transaction/EXPERIMENTAL_receipt.md index 1edc574..45aa8a2 100644 --- a/static/ru/rpcs/transaction/EXPERIMENTAL_receipt.md +++ b/static/ru/rpcs/transaction/EXPERIMENTAL_receipt.md @@ -240,3 +240,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/transaction/EXPERIMENTAL_receipt/index.md b/static/ru/rpcs/transaction/EXPERIMENTAL_receipt/index.md index 1edc574..45aa8a2 100644 --- a/static/ru/rpcs/transaction/EXPERIMENTAL_receipt/index.md +++ b/static/ru/rpcs/transaction/EXPERIMENTAL_receipt/index.md @@ -240,3 +240,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/transaction/EXPERIMENTAL_tx_status.md b/static/ru/rpcs/transaction/EXPERIMENTAL_tx_status.md index 3f5e77a..18611b9 100644 --- a/static/ru/rpcs/transaction/EXPERIMENTAL_tx_status.md +++ b/static/ru/rpcs/transaction/EXPERIMENTAL_tx_status.md @@ -294,3 +294,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/transaction/EXPERIMENTAL_tx_status/index.md b/static/ru/rpcs/transaction/EXPERIMENTAL_tx_status/index.md index 3f5e77a..18611b9 100644 --- a/static/ru/rpcs/transaction/EXPERIMENTAL_tx_status/index.md +++ b/static/ru/rpcs/transaction/EXPERIMENTAL_tx_status/index.md @@ -294,3 +294,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/transaction/broadcast_tx_async.md b/static/ru/rpcs/transaction/broadcast_tx_async.md index 74dfbb5..dc53455 100644 --- a/static/ru/rpcs/transaction/broadcast_tx_async.md +++ b/static/ru/rpcs/transaction/broadcast_tx_async.md @@ -209,3 +209,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/transaction/broadcast_tx_async/index.md b/static/ru/rpcs/transaction/broadcast_tx_async/index.md index 74dfbb5..dc53455 100644 --- a/static/ru/rpcs/transaction/broadcast_tx_async/index.md +++ b/static/ru/rpcs/transaction/broadcast_tx_async/index.md @@ -209,3 +209,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/transaction/broadcast_tx_commit.md b/static/ru/rpcs/transaction/broadcast_tx_commit.md index 9059380..6dcd64b 100644 --- a/static/ru/rpcs/transaction/broadcast_tx_commit.md +++ b/static/ru/rpcs/transaction/broadcast_tx_commit.md @@ -275,3 +275,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/transaction/broadcast_tx_commit/index.md b/static/ru/rpcs/transaction/broadcast_tx_commit/index.md index 9059380..6dcd64b 100644 --- a/static/ru/rpcs/transaction/broadcast_tx_commit/index.md +++ b/static/ru/rpcs/transaction/broadcast_tx_commit/index.md @@ -275,3 +275,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/transaction/send_tx.md b/static/ru/rpcs/transaction/send_tx.md index eff9f55..9d0deb0 100644 --- a/static/ru/rpcs/transaction/send_tx.md +++ b/static/ru/rpcs/transaction/send_tx.md @@ -277,3 +277,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/transaction/send_tx/index.md b/static/ru/rpcs/transaction/send_tx/index.md index eff9f55..9d0deb0 100644 --- a/static/ru/rpcs/transaction/send_tx/index.md +++ b/static/ru/rpcs/transaction/send_tx/index.md @@ -277,3 +277,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/transaction/tx_status.md b/static/ru/rpcs/transaction/tx_status.md index db41a58..a11a25c 100644 --- a/static/ru/rpcs/transaction/tx_status.md +++ b/static/ru/rpcs/transaction/tx_status.md @@ -292,3 +292,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/transaction/tx_status/index.md b/static/ru/rpcs/transaction/tx_status/index.md index db41a58..a11a25c 100644 --- a/static/ru/rpcs/transaction/tx_status/index.md +++ b/static/ru/rpcs/transaction/tx_status/index.md @@ -292,3 +292,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/validators/EXPERIMENTAL_validators_ordered.md b/static/ru/rpcs/validators/EXPERIMENTAL_validators_ordered.md index 2e4ea61..a8a1ab9 100644 --- a/static/ru/rpcs/validators/EXPERIMENTAL_validators_ordered.md +++ b/static/ru/rpcs/validators/EXPERIMENTAL_validators_ordered.md @@ -203,3 +203,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/validators/EXPERIMENTAL_validators_ordered/index.md b/static/ru/rpcs/validators/EXPERIMENTAL_validators_ordered/index.md index 2e4ea61..a8a1ab9 100644 --- a/static/ru/rpcs/validators/EXPERIMENTAL_validators_ordered/index.md +++ b/static/ru/rpcs/validators/EXPERIMENTAL_validators_ordered/index.md @@ -203,3 +203,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/validators/validators_by_epoch.md b/static/ru/rpcs/validators/validators_by_epoch.md index a603445..8086de3 100644 --- a/static/ru/rpcs/validators/validators_by_epoch.md +++ b/static/ru/rpcs/validators/validators_by_epoch.md @@ -291,3 +291,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/validators/validators_by_epoch/index.md b/static/ru/rpcs/validators/validators_by_epoch/index.md index a603445..8086de3 100644 --- a/static/ru/rpcs/validators/validators_by_epoch/index.md +++ b/static/ru/rpcs/validators/validators_by_epoch/index.md @@ -291,3 +291,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/validators/validators_current.md b/static/ru/rpcs/validators/validators_current.md index 265ac1e..7a6bfb8 100644 --- a/static/ru/rpcs/validators/validators_current.md +++ b/static/ru/rpcs/validators/validators_current.md @@ -282,3 +282,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/rpcs/validators/validators_current/index.md b/static/ru/rpcs/validators/validators_current/index.md index 265ac1e..7a6bfb8 100644 --- a/static/ru/rpcs/validators/validators_current/index.md +++ b/static/ru/rpcs/validators/validators_current/index.md @@ -282,3 +282,10 @@ "refName": "JsonRpcResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/snapshots.md b/static/ru/snapshots.md index 39c4d48..037bee2 100644 --- a/static/ru/snapshots.md +++ b/static/ru/snapshots.md @@ -47,7 +47,18 @@ sudo -v ; curl https://rclone.org/install.sh | sudo bash Требования к узлам смотрите в [nearcore](https://github.com/near/nearcore?tab=readme-ov-file#about-near), а исходники скриптов загрузки, которые используются в этих руководствах, — в [fastnear/static](https://github.com/fastnear/static). +## Нужен сценарий? + +Используйте [примеры снапшотов](https://docs.fastnear.com/ru/snapshots/examples) для практических примеров: выбора между оптимизированным `fast-rpc`, стандартным восстановлением RPC и архивными путями с разделением горячих и холодных данных. + ## Выберите сеть - [Снапшоты mainnet](https://docs.fastnear.com/ru/snapshots/mainnet) - [Снапшоты testnet](https://docs.fastnear.com/ru/snapshots/testnet) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/snapshots/examples.md b/static/ru/snapshots/examples.md new file mode 100644 index 0000000..83f91fa --- /dev/null +++ b/static/ru/snapshots/examples.md @@ -0,0 +1,65 @@ +**Источник:** [https://docs.fastnear.com/ru/snapshots/examples](https://docs.fastnear.com/ru/snapshots/examples) + +## Пути восстановления mainnet + +Выберите один класс — optimized `fast-rpc`, standard RPC или archival — и выполняйте только команды этого пути. Смешивание классов приводит к несогласованным данным узла. + +FastNear поддерживает эти скрипты ради скорости восстановления. Если в вашей среде требуется review изменений, скачайте скрипт и проверьте его перед запуском (вместо прямой передачи через pipe в `bash`). + +### Optimized mainnet `fast-rpc` + +```bash +DATA_PATH=~/.near/data + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone.sh \ + | DATA_PATH="$DATA_PATH" CHAIN_ID=mainnet RPC_TYPE=fast-rpc bash +``` + +### Standard mainnet RPC + +```bash +DATA_PATH=~/.near/data + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone.sh \ + | DATA_PATH="$DATA_PATH" CHAIN_ID=mainnet bash +``` + +### Archival mainnet + +Для archival нужны две загрузки из *одного и того же* среза снапшота. Зафиксируйте одно значение `LATEST` и переиспользуйте его и для hot-, и для cold-data — смешивание высот даёт внутренне несогласованный набор данных и удивляет nearcore на этапе настройки. + +```bash +HOT_DATA_PATH=~/.near/data +COLD_DATA_PATH=/mnt/hdds/cold-data + +LATEST="$(curl -s "https://snapshot.neardata.xyz/mainnet/archival/latest.txt")" +echo "Latest archival mainnet snapshot block: $LATEST" + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh \ + | DATA_TYPE=hot-data DATA_PATH="$HOT_DATA_PATH" CHAIN_ID=mainnet BLOCK="$LATEST" bash + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh \ + | DATA_TYPE=cold-data DATA_PATH="$COLD_DATA_PATH" CHAIN_ID=mainnet BLOCK="$LATEST" bash +``` + +## Частые ошибки + +- Использовать документацию по снапшотам, когда задача на самом деле про чтение данных цепочки. +- Выбирать archival-восстановление, когда достаточно standard или optimized RPC. +- Забывать про разделение hot/cold-хранилища для archival-данных. +- Переходить к командам до выбора сети и цели узла. + +## Связанные страницы + +- [Обзор snapshot](https://docs.fastnear.com/ru/snapshots) +- [Снапшоты mainnet](https://docs.fastnear.com/ru/snapshots/mainnet) +- [Снапшоты testnet](https://docs.fastnear.com/ru/snapshots/testnet) +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [NEAR Data API](https://docs.fastnear.com/ru/neardata) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/snapshots/examples/index.md b/static/ru/snapshots/examples/index.md new file mode 100644 index 0000000..83f91fa --- /dev/null +++ b/static/ru/snapshots/examples/index.md @@ -0,0 +1,65 @@ +**Источник:** [https://docs.fastnear.com/ru/snapshots/examples](https://docs.fastnear.com/ru/snapshots/examples) + +## Пути восстановления mainnet + +Выберите один класс — optimized `fast-rpc`, standard RPC или archival — и выполняйте только команды этого пути. Смешивание классов приводит к несогласованным данным узла. + +FastNear поддерживает эти скрипты ради скорости восстановления. Если в вашей среде требуется review изменений, скачайте скрипт и проверьте его перед запуском (вместо прямой передачи через pipe в `bash`). + +### Optimized mainnet `fast-rpc` + +```bash +DATA_PATH=~/.near/data + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone.sh \ + | DATA_PATH="$DATA_PATH" CHAIN_ID=mainnet RPC_TYPE=fast-rpc bash +``` + +### Standard mainnet RPC + +```bash +DATA_PATH=~/.near/data + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone.sh \ + | DATA_PATH="$DATA_PATH" CHAIN_ID=mainnet bash +``` + +### Archival mainnet + +Для archival нужны две загрузки из *одного и того же* среза снапшота. Зафиксируйте одно значение `LATEST` и переиспользуйте его и для hot-, и для cold-data — смешивание высот даёт внутренне несогласованный набор данных и удивляет nearcore на этапе настройки. + +```bash +HOT_DATA_PATH=~/.near/data +COLD_DATA_PATH=/mnt/hdds/cold-data + +LATEST="$(curl -s "https://snapshot.neardata.xyz/mainnet/archival/latest.txt")" +echo "Latest archival mainnet snapshot block: $LATEST" + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh \ + | DATA_TYPE=hot-data DATA_PATH="$HOT_DATA_PATH" CHAIN_ID=mainnet BLOCK="$LATEST" bash + +curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh \ + | DATA_TYPE=cold-data DATA_PATH="$COLD_DATA_PATH" CHAIN_ID=mainnet BLOCK="$LATEST" bash +``` + +## Частые ошибки + +- Использовать документацию по снапшотам, когда задача на самом деле про чтение данных цепочки. +- Выбирать archival-восстановление, когда достаточно standard или optimized RPC. +- Забывать про разделение hot/cold-хранилища для archival-данных. +- Переходить к командам до выбора сети и цели узла. + +## Связанные страницы + +- [Обзор snapshot](https://docs.fastnear.com/ru/snapshots) +- [Снапшоты mainnet](https://docs.fastnear.com/ru/snapshots/mainnet) +- [Снапшоты testnet](https://docs.fastnear.com/ru/snapshots/testnet) +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [NEAR Data API](https://docs.fastnear.com/ru/neardata) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/snapshots/index.md b/static/ru/snapshots/index.md index 39c4d48..037bee2 100644 --- a/static/ru/snapshots/index.md +++ b/static/ru/snapshots/index.md @@ -47,7 +47,18 @@ sudo -v ; curl https://rclone.org/install.sh | sudo bash Требования к узлам смотрите в [nearcore](https://github.com/near/nearcore?tab=readme-ov-file#about-near), а исходники скриптов загрузки, которые используются в этих руководствах, — в [fastnear/static](https://github.com/fastnear/static). +## Нужен сценарий? + +Используйте [примеры снапшотов](https://docs.fastnear.com/ru/snapshots/examples) для практических примеров: выбора между оптимизированным `fast-rpc`, стандартным восстановлением RPC и архивными путями с разделением горячих и холодных данных. + ## Выберите сеть - [Снапшоты mainnet](https://docs.fastnear.com/ru/snapshots/mainnet) - [Снапшоты testnet](https://docs.fastnear.com/ru/snapshots/testnet) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/snapshots/mainnet.md b/static/ru/snapshots/mainnet.md index 4d95e90..00af631 100644 --- a/static/ru/snapshots/mainnet.md +++ b/static/ru/snapshots/mainnet.md @@ -128,3 +128,10 @@ curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/ ```bash curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh | DATA_TYPE=cold-data DATA_PATH=/mnt/hdds/cold-data CHAIN_ID=mainnet BLOCK=$LATEST bash ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/snapshots/mainnet/index.md b/static/ru/snapshots/mainnet/index.md index 4d95e90..00af631 100644 --- a/static/ru/snapshots/mainnet/index.md +++ b/static/ru/snapshots/mainnet/index.md @@ -128,3 +128,10 @@ curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/ ```bash curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh | DATA_TYPE=cold-data DATA_PATH=/mnt/hdds/cold-data CHAIN_ID=mainnet BLOCK=$LATEST bash ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/snapshots/testnet.md b/static/ru/snapshots/testnet.md index a0ce443..eaf4788 100644 --- a/static/ru/snapshots/testnet.md +++ b/static/ru/snapshots/testnet.md @@ -77,3 +77,10 @@ echo "Latest snapshot block: $LATEST" ```bash curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh | DATA_TYPE=hot-data DATA_PATH=~/.near/data CHAIN_ID=testnet BLOCK=$LATEST bash ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/snapshots/testnet/index.md b/static/ru/snapshots/testnet/index.md index a0ce443..eaf4788 100644 --- a/static/ru/snapshots/testnet/index.md +++ b/static/ru/snapshots/testnet/index.md @@ -77,3 +77,10 @@ echo "Latest snapshot block: $LATEST" ```bash curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/fastnear/static/refs/heads/main/down_rclone_archival.sh | DATA_TYPE=hot-data DATA_PATH=~/.near/data CHAIN_ID=testnet BLOCK=$LATEST bash ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/structured-data/site-graph.json b/static/ru/structured-data/site-graph.json index b6b609e..13c79c9 100644 --- a/static/ru/structured-data/site-graph.json +++ b/static/ru/structured-data/site-graph.json @@ -3882,6 +3882,19 @@ "routeType": "docs", "url": "https://docs.fastnear.com/ru/api" }, + { + "entityIds": { + "familyIds": [], + "mainEntityId": null, + "pageId": "https://docs.fastnear.com/ru/api/examples#page" + }, + "indexable": true, + "markdownMirrorUrl": "https://docs.fastnear.com/ru/api/examples.md", + "pageSchemaType": "TechArticle", + "route": "/ru/api/examples", + "routeType": "docs", + "url": "https://docs.fastnear.com/ru/api/examples" + }, { "entityIds": { "familyIds": [], @@ -4718,6 +4731,19 @@ "routeType": "docs", "url": "https://docs.fastnear.com/ru/fastdata/kv/all-by-predecessor" }, + { + "entityIds": { + "familyIds": [], + "mainEntityId": null, + "pageId": "https://docs.fastnear.com/ru/fastdata/kv/examples#page" + }, + "indexable": true, + "markdownMirrorUrl": "https://docs.fastnear.com/ru/fastdata/kv/examples.md", + "pageSchemaType": "TechArticle", + "route": "/ru/fastdata/kv/examples", + "routeType": "docs", + "url": "https://docs.fastnear.com/ru/fastdata/kv/examples" + }, { "entityIds": { "familyIds": [ @@ -4941,6 +4967,19 @@ "routeType": "docs", "url": "https://docs.fastnear.com/ru/neardata/block-shard" }, + { + "entityIds": { + "familyIds": [], + "mainEntityId": null, + "pageId": "https://docs.fastnear.com/ru/neardata/examples#page" + }, + "indexable": true, + "markdownMirrorUrl": "https://docs.fastnear.com/ru/neardata/examples.md", + "pageSchemaType": "TechArticle", + "route": "/ru/neardata/examples", + "routeType": "docs", + "url": "https://docs.fastnear.com/ru/neardata/examples" + }, { "entityIds": { "familyIds": [ @@ -5199,6 +5238,19 @@ "routeType": "docs", "url": "https://docs.fastnear.com/ru/rpc/contract/view-state" }, + { + "entityIds": { + "familyIds": [], + "mainEntityId": null, + "pageId": "https://docs.fastnear.com/ru/rpc/examples#page" + }, + "indexable": true, + "markdownMirrorUrl": "https://docs.fastnear.com/ru/rpc/examples.md", + "pageSchemaType": "TechArticle", + "route": "/ru/rpc/examples", + "routeType": "docs", + "url": "https://docs.fastnear.com/ru/rpc/examples" + }, { "entityIds": { "familyIds": [ @@ -6247,6 +6299,19 @@ "routeType": "docs", "url": "https://docs.fastnear.com/ru/snapshots" }, + { + "entityIds": { + "familyIds": [], + "mainEntityId": null, + "pageId": "https://docs.fastnear.com/ru/snapshots/examples#page" + }, + "indexable": true, + "markdownMirrorUrl": "https://docs.fastnear.com/ru/snapshots/examples.md", + "pageSchemaType": "TechArticle", + "route": "/ru/snapshots/examples", + "routeType": "docs", + "url": "https://docs.fastnear.com/ru/snapshots/examples" + }, { "entityIds": { "familyIds": [], @@ -6288,6 +6353,19 @@ "routeType": "docs", "url": "https://docs.fastnear.com/ru/transfers" }, + { + "entityIds": { + "familyIds": [], + "mainEntityId": null, + "pageId": "https://docs.fastnear.com/ru/transfers/examples#page" + }, + "indexable": true, + "markdownMirrorUrl": "https://docs.fastnear.com/ru/transfers/examples.md", + "pageSchemaType": "TechArticle", + "route": "/ru/transfers/examples", + "routeType": "docs", + "url": "https://docs.fastnear.com/ru/transfers/examples" + }, { "entityIds": { "familyIds": [ @@ -6363,6 +6441,32 @@ "routeType": "docs", "url": "https://docs.fastnear.com/ru/tx/blocks" }, + { + "entityIds": { + "familyIds": [], + "mainEntityId": null, + "pageId": "https://docs.fastnear.com/ru/tx/examples#page" + }, + "indexable": true, + "markdownMirrorUrl": "https://docs.fastnear.com/ru/tx/examples.md", + "pageSchemaType": "TechArticle", + "route": "/ru/tx/examples", + "routeType": "docs", + "url": "https://docs.fastnear.com/ru/tx/examples" + }, + { + "entityIds": { + "familyIds": [], + "mainEntityId": null, + "pageId": "https://docs.fastnear.com/ru/tx/examples/berry-club#page" + }, + "indexable": true, + "markdownMirrorUrl": "https://docs.fastnear.com/ru/tx/examples/berry-club.md", + "pageSchemaType": "TechArticle", + "route": "/ru/tx/examples/berry-club", + "routeType": "docs", + "url": "https://docs.fastnear.com/ru/tx/examples/berry-club" + }, { "entityIds": { "familyIds": [ @@ -6378,6 +6482,19 @@ "routeType": "docs", "url": "https://docs.fastnear.com/ru/tx/receipt" }, + { + "entityIds": { + "familyIds": [], + "mainEntityId": null, + "pageId": "https://docs.fastnear.com/ru/tx/socialdb-proofs#page" + }, + "indexable": true, + "markdownMirrorUrl": "https://docs.fastnear.com/ru/tx/socialdb-proofs.md", + "pageSchemaType": "TechArticle", + "route": "/ru/tx/socialdb-proofs", + "routeType": "docs", + "url": "https://docs.fastnear.com/ru/tx/socialdb-proofs" + }, { "entityIds": { "familyIds": [ diff --git a/static/ru/transfers.md b/static/ru/transfers.md index b69a6be..831666b 100644 --- a/static/ru/transfers.md +++ b/static/ru/transfers.md @@ -58,6 +58,10 @@ https://transfers.main.fastnear.com - [Запрос переводов](https://docs.fastnear.com/ru/transfers/query) — лента по аккаунту с фильтрами по направлению, активу, сумме и времени +## Нужен сценарий? + +Используйте [Transfers API Examples](https://docs.fastnear.com/ru/transfers/examples) для практических примеров: узкие поиски переводов, пагинация через `resume_token` и переход к более широкому расследованию транзакций. + ## Устранение неполадок ### Нужны полные метаданные транзакции @@ -67,3 +71,10 @@ https://transfers.main.fastnear.com ### `resume_token` перестал работать Считайте токен непрозрачным и переиспользуйте его только с тем же эндпоинтом и фильтрами, которые его вернули. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/transfers/examples.md b/static/ru/transfers/examples.md new file mode 100644 index 0000000..0655a42 --- /dev/null +++ b/static/ru/transfers/examples.md @@ -0,0 +1,110 @@ +**Источник:** [https://docs.fastnear.com/ru/transfers/examples](https://docs.fastnear.com/ru/transfers/examples) + +## Примеры + +Эти shell-примеры работают и на публичных Transfers и Transactions endpoint-ах. Если `FASTNEAR_API_KEY` уже задан в окружении, сниппеты автоматически пробросят его как bearer-заголовок. + +### Какая у этого аккаунта свежая активность по переводам? + +`/v0/transfers` всего с `account_id` и `desc: true` возвращает самые свежие переводы, касающиеся этого аккаунта, по всем типам активов, в обоих направлениях сразу. В каждой строке уже есть `human_amount`, `asset_id` и `transaction_id`, так что этот поток заодно служит быстрым сканом активности до того, как вы достанете фильтры. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id: $account_id, desc: true, limit: 5}')" \ + | jq '{ + recent: [.transfers[] | { + block_height, + asset_id, + human_amount, + other_account_id, + transfer_type, + tx: .transaction_id + }] + }' +``` + +Для `root.near` последние строки смешивают активы `FtTransfer` и `MtTransfer`. `asset_id` использует URI по NEP-стандартам (`native:near`, `nep141:...`, `nep245:...`), так что одно поле уже подсказывает, к какому стандарту тянуться дальше. Положительный `human_amount` означает, что аккаунт получил; отрицательный — что отправил. `other_account_id: null` — норма для multi-token-форм, где контрагент сидит внутри границы контракта, а не как отдельный аккаунт верхнего уровня. + +### Отфильтровать и листать ленту переводов одного аккаунта + +`/v0/transfers` возвращает отфильтрованную ленту плюс `resume_token`, который вы переиспользуете *без изменения фильтров*, чтобы продолжать листать. В каждой строке уже есть `human_amount`, `usd_amount`, `transaction_id` и `receipt_id` — большинство audit-вопросов закрываются без второго запроса. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +FEED="$(curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + account_id: $account_id, + direction: "receiver", + asset_id: "native:near", + min_amount: "1000000000000000000000000", + desc: true, + limit: 10 + }')")" + +echo "$FEED" | jq '{ + resume_token, + transfers: [.transfers[] | {block_height, amount, human_amount, usd_amount, other_account_id, transaction_id, receipt_id}] +}' +``` + +Для зафиксированного аккаунта это возвращает недавние входящие native-NEAR переводы не меньше 1 NEAR — в примерных строках видны native-переводы с `escrow.ai.near` и уже посчитанным USD. Чтобы получить следующую страницу, отправьте то же тело с верхнеуровневым `resume_token: ""`; изменение любого другого фильтра делает токен недействительным. + +Когда одной строке нужна точка исполнения, возьмите её `receipt_id` и сразу обратитесь к `/v0/receipt`: + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +FEED="$(curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + account_id: $account_id, + direction: "receiver", + asset_id: "native:near", + min_amount: "1000000000000000000000000", + desc: true, + limit: 10 + }')")" +RECEIPT_ID="$(echo "$FEED" | jq -r '.transfers[0].receipt_id')" + +curl -s "https://tx.main.fastnear.com/v0/receipt" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg receipt_id "$RECEIPT_ID" '{receipt_id: $receipt_id}')" \ + | jq '.receipt | {receipt_id, transaction_hash, receiver_id, predecessor_id, tx_block_height, is_success}' +``` + +Это тот же переход, что описан в [Превратить один receipt ID в читаемую историю транзакции](https://docs.fastnear.com/ru/tx/examples#receipt-id-to-readable-story) — один запрос возвращает и квитанцию, и её родительскую транзакцию целиком. + +## Частые ошибки + +- Использовать Transfers API, когда пользователю на самом деле нужны балансы, активы или сводки аккаунта. +- Считать историю переводов полной историей исполнения. +- Переиспользовать `resume_token` с другими фильтрами. + +## Связанные страницы + +- [Transfers API](https://docs.fastnear.com/ru/transfers) +- [Transactions API](https://docs.fastnear.com/ru/tx) +- [FastNear API](https://docs.fastnear.com/ru/api) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/transfers/examples/index.md b/static/ru/transfers/examples/index.md new file mode 100644 index 0000000..0655a42 --- /dev/null +++ b/static/ru/transfers/examples/index.md @@ -0,0 +1,110 @@ +**Источник:** [https://docs.fastnear.com/ru/transfers/examples](https://docs.fastnear.com/ru/transfers/examples) + +## Примеры + +Эти shell-примеры работают и на публичных Transfers и Transactions endpoint-ах. Если `FASTNEAR_API_KEY` уже задан в окружении, сниппеты автоматически пробросят его как bearer-заголовок. + +### Какая у этого аккаунта свежая активность по переводам? + +`/v0/transfers` всего с `account_id` и `desc: true` возвращает самые свежие переводы, касающиеся этого аккаунта, по всем типам активов, в обоих направлениях сразу. В каждой строке уже есть `human_amount`, `asset_id` и `transaction_id`, так что этот поток заодно служит быстрым сканом активности до того, как вы достанете фильтры. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{account_id: $account_id, desc: true, limit: 5}')" \ + | jq '{ + recent: [.transfers[] | { + block_height, + asset_id, + human_amount, + other_account_id, + transfer_type, + tx: .transaction_id + }] + }' +``` + +Для `root.near` последние строки смешивают активы `FtTransfer` и `MtTransfer`. `asset_id` использует URI по NEP-стандартам (`native:near`, `nep141:...`, `nep245:...`), так что одно поле уже подсказывает, к какому стандарту тянуться дальше. Положительный `human_amount` означает, что аккаунт получил; отрицательный — что отправил. `other_account_id: null` — норма для multi-token-форм, где контрагент сидит внутри границы контракта, а не как отдельный аккаунт верхнего уровня. + +### Отфильтровать и листать ленту переводов одного аккаунта + +`/v0/transfers` возвращает отфильтрованную ленту плюс `resume_token`, который вы переиспользуете *без изменения фильтров*, чтобы продолжать листать. В каждой строке уже есть `human_amount`, `usd_amount`, `transaction_id` и `receipt_id` — большинство audit-вопросов закрываются без второго запроса. + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +FEED="$(curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + account_id: $account_id, + direction: "receiver", + asset_id: "native:near", + min_amount: "1000000000000000000000000", + desc: true, + limit: 10 + }')")" + +echo "$FEED" | jq '{ + resume_token, + transfers: [.transfers[] | {block_height, amount, human_amount, usd_amount, other_account_id, transaction_id, receipt_id}] +}' +``` + +Для зафиксированного аккаунта это возвращает недавние входящие native-NEAR переводы не меньше 1 NEAR — в примерных строках видны native-переводы с `escrow.ai.near` и уже посчитанным USD. Чтобы получить следующую страницу, отправьте то же тело с верхнеуровневым `resume_token: ""`; изменение любого другого фильтра делает токен недействительным. + +Когда одной строке нужна точка исполнения, возьмите её `receipt_id` и сразу обратитесь к `/v0/receipt`: + +```bash +ACCOUNT_ID=root.near +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +FEED="$(curl -s "https://transfers.main.fastnear.com/v0/transfers" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" '{ + account_id: $account_id, + direction: "receiver", + asset_id: "native:near", + min_amount: "1000000000000000000000000", + desc: true, + limit: 10 + }')")" +RECEIPT_ID="$(echo "$FEED" | jq -r '.transfers[0].receipt_id')" + +curl -s "https://tx.main.fastnear.com/v0/receipt" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg receipt_id "$RECEIPT_ID" '{receipt_id: $receipt_id}')" \ + | jq '.receipt | {receipt_id, transaction_hash, receiver_id, predecessor_id, tx_block_height, is_success}' +``` + +Это тот же переход, что описан в [Превратить один receipt ID в читаемую историю транзакции](https://docs.fastnear.com/ru/tx/examples#receipt-id-to-readable-story) — один запрос возвращает и квитанцию, и её родительскую транзакцию целиком. + +## Частые ошибки + +- Использовать Transfers API, когда пользователю на самом деле нужны балансы, активы или сводки аккаунта. +- Считать историю переводов полной историей исполнения. +- Переиспользовать `resume_token` с другими фильтрами. + +## Связанные страницы + +- [Transfers API](https://docs.fastnear.com/ru/transfers) +- [Transactions API](https://docs.fastnear.com/ru/tx) +- [FastNear API](https://docs.fastnear.com/ru/api) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/transfers/index.md b/static/ru/transfers/index.md index b69a6be..831666b 100644 --- a/static/ru/transfers/index.md +++ b/static/ru/transfers/index.md @@ -58,6 +58,10 @@ https://transfers.main.fastnear.com - [Запрос переводов](https://docs.fastnear.com/ru/transfers/query) — лента по аккаунту с фильтрами по направлению, активу, сумме и времени +## Нужен сценарий? + +Используйте [Transfers API Examples](https://docs.fastnear.com/ru/transfers/examples) для практических примеров: узкие поиски переводов, пагинация через `resume_token` и переход к более широкому расследованию транзакций. + ## Устранение неполадок ### Нужны полные метаданные транзакции @@ -67,3 +71,10 @@ https://transfers.main.fastnear.com ### `resume_token` перестал работать Считайте токен непрозрачным и переиспользуйте его только с тем же эндпоинтом и фильтрами, которые его вернули. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/transfers/query.md b/static/ru/transfers/query.md index 7678bfe..c4c19c1 100644 --- a/static/ru/transfers/query.md +++ b/static/ru/transfers/query.md @@ -383,3 +383,10 @@ "refName": "TransfersResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/transfers/query/index.md b/static/ru/transfers/query/index.md index 7678bfe..c4c19c1 100644 --- a/static/ru/transfers/query/index.md +++ b/static/ru/transfers/query/index.md @@ -383,3 +383,10 @@ "refName": "TransfersResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx.md b/static/ru/tx.md index bf3aadc..565c487 100644 --- a/static/ru/tx.md +++ b/static/ru/tx.md @@ -40,6 +40,10 @@ https://tx.test.fastnear.com - [Поиск квитанции](https://docs.fastnear.com/ru/tx/receipt) — для расследования цепочки исполнения. - [Диапазон блоков](https://docs.fastnear.com/ru/tx/blocks) — когда нужен ограниченный по диапазону просмотр истории. +## Нужен сценарий? + +Используйте [примеры API транзакций](https://docs.fastnear.com/ru/tx/examples) для практических примеров: поиска транзакций, расследования квитанций, истории аккаунта и анализа диапазонов блоков. + ## Устранение неполадок ### Я ожидал, что здесь можно отправлять транзакции @@ -53,3 +57,10 @@ https://tx.test.fastnear.com ### Мне нужен только один канонический результат статуса транзакции из RPC Используйте сырой RPC вместо индексированного семейства истории. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/account.md b/static/ru/tx/account.md index ab634bb..c299b01 100644 --- a/static/ru/tx/account.md +++ b/static/ru/tx/account.md @@ -414,3 +414,10 @@ "refName": "AccountResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/account/index.md b/static/ru/tx/account/index.md index ab634bb..c299b01 100644 --- a/static/ru/tx/account/index.md +++ b/static/ru/tx/account/index.md @@ -414,3 +414,10 @@ "refName": "AccountResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/block.md b/static/ru/tx/block.md index f603d51..bcb016c 100644 --- a/static/ru/tx/block.md +++ b/static/ru/tx/block.md @@ -589,3 +589,10 @@ "refName": "BlockResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/block/index.md b/static/ru/tx/block/index.md index f603d51..bcb016c 100644 --- a/static/ru/tx/block/index.md +++ b/static/ru/tx/block/index.md @@ -589,3 +589,10 @@ "refName": "BlockResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/blocks.md b/static/ru/tx/blocks.md index 5764882..6bdc239 100644 --- a/static/ru/tx/blocks.md +++ b/static/ru/tx/blocks.md @@ -268,3 +268,10 @@ "refName": "BlocksResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/blocks/index.md b/static/ru/tx/blocks/index.md index 5764882..6bdc239 100644 --- a/static/ru/tx/blocks/index.md +++ b/static/ru/tx/blocks/index.md @@ -268,3 +268,10 @@ "refName": "BlocksResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/examples.md b/static/ru/tx/examples.md new file mode 100644 index 0000000..6d7cfc9 --- /dev/null +++ b/static/ru/tx/examples.md @@ -0,0 +1,253 @@ +**Источник:** [https://docs.fastnear.com/ru/tx/examples](https://docs.fastnear.com/ru/tx/examples) + +## Начните здесь + +Все shell-примеры ниже работают на публичных Transactions API-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### У меня один хеш транзакции. Что произошло? + +Вставьте хеш в `POST /v0/transactions` — один ответ обычно содержит всю историю. + +```bash +TX_HASH=7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq '{ + hash: .transactions[0].transaction.hash, + signer_id: .transactions[0].transaction.signer_id, + receiver_id: .transactions[0].transaction.receiver_id, + included_block_height: .transactions[0].execution_outcome.block_height, + actions: (.transactions[0].transaction.actions | map(if type == "string" then . else keys[0] end)), + first_receipt_id: .transactions[0].execution_outcome.outcome.status.SuccessReceiptId, + receipt_count: (.transactions[0].receipts | length) + }' +``` + +Для зафиксированного хеша `root.near` отправил один `Transfer` на `escrow.ai.near` в блоке `188976785`, с передачей в receipt `B8QzHQZ6VnUVy8zaVXCEkWuSs7MPb34yoHYixZV3Zdj1`. Если `receipt_count > 1` или следующий вопрос касается поведения на уровне receipt, переходите к [Какой receipt испустил этот лог или событие?](#какой-receipt-испустил-этот-лог-или-событие) или [`POST /v0/receipt`](https://docs.fastnear.com/ru/tx/receipt). + +### Какой receipt испустил этот лог или событие? + +Выведите список всех receipt транзакции с логами и флагом, содержат ли их логи ваш фрагмент. Совпадение доказывается, а не угадывается: у зафиксированной транзакции один receipt логирует `Transfer`, другой — `Refund`, и только сторона `Refund` переключается в `true`. + +```bash +TX_HASH=2KhhB1uDScGCFQfVchep7DiZTGTxMcgfUYHNzwf5e6uL +LOG_FRAGMENT=Refund +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg fragment "$LOG_FRAGMENT" ' + [ + .transactions[0].receipts[] + | select((.execution_outcome.outcome.logs | length) > 0) + | { + receipt_id: .receipt.receipt_id, + receiver_id: .receipt.receiver_id, + method_name: (.receipt.receipt.Action.actions[0] + | if type == "string" then . else (.FunctionCall.method_name // keys[0]) end), + matches_fragment: any(.execution_outcome.outcome.logs[]?; contains($fragment)), + logs: .execution_outcome.outcome.logs + } + ]' +``` + +Фрагмент `Refund` атрибутируется receipt `9sLHQpaGz3NnMNMn8zGrDUSyktR1q6ts2otr9mHkfD1w` на `wrap.near`, метод `ft_resolve_transfer`. Логи receipt живут на receipts, а не на транзакции, поэтому одного прохода достаточно — более глубокая async-трассировка не нужна. + +### Превратить один receipt ID в читаемую историю транзакции {#receipt-id-to-readable-story} + +`POST /v0/receipt` возвращает запись receipt **и** его полную родительскую транзакцию в одном ответе, поэтому единственного запроса хватает на всю историю — дополнительный `/v0/transactions` не нужен. + +```bash +RECEIPT_ID=B8QzHQZ6VnUVy8zaVXCEkWuSs7MPb34yoHYixZV3Zdj1 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/receipt" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg receipt_id "$RECEIPT_ID" '{receipt_id: $receipt_id}')" \ + | jq '{ + receipt: { + receipt_id: .receipt.receipt_id, + type: .receipt.receipt_type, + is_success: .receipt.is_success, + receipt_block: .receipt.block_height, + tx_block: .receipt.tx_block_height, + predecessor_id: .receipt.predecessor_id, + receiver_id: .receipt.receiver_id, + transaction_hash: .receipt.transaction_hash + }, + parent_transaction: { + signer_id: .transaction.transaction.signer_id, + receiver_id: .transaction.transaction.receiver_id, + action_types: (.transaction.transaction.actions | map(if type == "string" then . else keys[0] end)) + } + }' +``` + +Для зафиксированного receipt это возвращает `Action`-receipt от `root.near` к `escrow.ai.near`, который успешно выполнился в блоке `188976786`, через один блок после попадания родительской транзакции `7ZKnhzt2…`, — один `Transfer` (3.5 NEAR, в сыром `.transaction.transaction.actions` видимо как `3500000000000000000000000` yocto). Если интересным якорем становится родительская транзакция, хеш у вас уже есть — переиспользуйте его в [У меня один хеш транзакции. Что произошло?](#у-меня-один-хеш-транзакции-что-произошло). + +## Сбои и async + +### Доказать, что один провалившийся action откатил весь batch + +Один batch отправил `CreateAccount → Transfer → AddKey → FunctionCall`, и финальный вызов попал в отсутствующий метод. Индексированная запись транзакции уже несёт упорядоченный batch *и* точный сбой на уровне receipt, поэтому одного запроса хватает, чтобы ответить «что пытались и что сломалось»; проверка через `view_account` затем доказывает, что предыдущие actions откатились. + +```bash +TX_HASH=CrhH3xLzbNwNMGgZkgptXorwh8YmqxRGuA6Mc11MkU6M +NEW_ACCOUNT_ID=rollback-mo4vmkig.temp.mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.test.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq '{ + action_types: (.transactions[0].transaction.actions | map(if type == "string" then . else keys[0] end)), + final_method: .transactions[0].transaction.actions[3].FunctionCall.method_name, + tx_handoff: .transactions[0].execution_outcome.outcome.status, + receipt_failure: ( + first( + .transactions[0].receipts[] + | select(.execution_outcome.outcome.status.Failure != null) + | .execution_outcome.outcome.status.Failure.ActionError + ) + ) + }' +``` + +Статус на уровне транзакции — `SuccessReceiptId`: транзакция успешно передала свои batched actions в receipt. Сбой лежит слоем ниже на этом receipt: `index: 3` (именно `FunctionCall`), вид `CodeDoesNotExist` на `rollback-mo4vmkig.temp.mike.testnet`. `SuccessReceiptId` в tx-outcome означает «handoff прошёл», а не «всё завершилось» — реальная ловушка, если смотреть только на статус уровня транзакции. + +Теперь докажите откат предыдущих actions: спросите аккаунт, который batch *пытался* создать: + +```bash +NEW_ACCOUNT_ID=rollback-mo4vmkig.temp.mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.testnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$NEW_ACCOUNT_ID" '{ + jsonrpc: "2.0", id: "fastnear", method: "query", + params: {request_type: "view_account", account_id: $account_id, finality: "final"} + }')" \ + | jq '{error: .error.cause.name, requested_account_id: .error.cause.info.requested_account_id}' +``` + +`UNKNOWN_ACCOUNT` — это и есть доказательство. Если бы `CreateAccount` закрепился, `view_account` вернул бы результат; раз нет — предыдущие `Transfer` и `AddKey` из того же batched-receipt тоже не закрепились. + +### Когда транзакция выглядит успешной — что на самом деле произошло? + +Внешний `execution_outcome.outcome.status` рапортует `SuccessReceiptId`, как только сработал handoff первого receipt, — и ничего не говорит о том, успешны ли дочерние receipts и отработал ли callback на исходном контракте. Один pipeline над `/v0/transactions` отвечает сразу на все три вопроса. + +```bash +TX_HASH=2KhhB1uDScGCFQfVchep7DiZTGTxMcgfUYHNzwf5e6uL +ORIGIN_CONTRACT_ID=wrap.near +CALLBACK_METHOD=ft_resolve_transfer +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg origin "$ORIGIN_CONTRACT_ID" --arg callback "$CALLBACK_METHOD" '{ + outer: { + method: .transactions[0].transaction.actions[0].FunctionCall.method_name, + tx_handoff: (.transactions[0].execution_outcome.outcome.status | keys[0]) + }, + callback: { + expected_on: $origin, + method: $callback, + ran: any( + .transactions[0].receipts[]; + .receipt.receiver_id == $origin + and (.receipt.receipt.Action.actions[0].FunctionCall.method_name // "") == $callback + ) + }, + descendant_failures: [ + .transactions[0].receipts[] + | select(.execution_outcome.outcome.status.Failure != null) + | { + receiver_id: .receipt.receiver_id, + method: (.receipt.receipt.Action.actions[0].FunctionCall.method_name // "system"), + cause: .execution_outcome.outcome.status.Failure + } + ] + }' +``` + +Для зафиксированной транзакции `outer.method` — `ft_transfer_call`, а `outer.tx_handoff` — `SuccessReceiptId`: транзакция чисто запустила свой первый receipt, и если смотреть только сюда, можно назвать это победой. `descendant_failures` рассказывают вторую историю: `ft_on_transfer` на `v2.ref-finance.near` упал с `E51: contract paused` — DEX был на паузе во время этого свопа и не мог принять wrapped NEAR. `callback.ran: true` — третью: callback `ft_resolve_transfer` на `wrap.near` всё равно отработал. Сбой ниже по цепочке никогда не мешает callback исходного контракта — именно так NEP-141 возвращает отправителю средства, когда получатель их отклонил. + +Успех receipt не транзитивен. Протокол может чисто отдать handoff и при этом увидеть, как отцеплённая работа провалится позже; callback исходного контракта отработает в любом случае. Прочитайте эти три поля вместе — и async-история становится читаемой без ручного обхода цепочки receipts. Чтобы вытянуть сам лог `Refund`, переходите к [Какой receipt испустил этот лог или событие?](#какой-receipt-испустил-этот-лог-или-событие). + +### Сопоставить запрос OutLayer с его TEE-разрешением + +[OutLayer](https://outlayer.fastnear.com) разделяет один логический вызов на две транзакции: пользователь подписывает `request_execution` на `outlayer.near`, worker в Intel TDX запускает нужный WASM off-chain, затем `worker.outlayer.near` присылает результат через `submit_execution_output_and_resolve`. Обе половины несут один и тот же `request_id` — передайте оба tx-хеша в один запрос `/v0/transactions` и извлеките это поле с каждой стороны, чтобы подтвердить пару. + +```bash +REQUEST_TX=BZDQAxEdpQ9wUGXmXTa2APwFLDTTqTy5ucrBPsfgZeyz +WORKER_TX=3NYD4Mkn5cwkuVkGP9PPoiJ9PB5Vr7v6r8CwSswtHVA3 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg a "$REQUEST_TX" --arg b "$WORKER_TX" '{tx_hashes: [$a, $b]}')" \ + | jq '[ + .transactions[] + | { + role: (if .transaction.actions[0].FunctionCall.method_name == "request_execution" + then "request" else "worker" end), + hash: .transaction.hash, + signer: .transaction.signer_id, + method: .transaction.actions[0].FunctionCall.method_name, + block: .execution_outcome.block_height, + request_id: ( + if .transaction.actions[0].FunctionCall.method_name == "request_execution" + then (.receipts[0].execution_outcome.outcome.logs[] | select(startswith("EVENT_JSON")) + | sub("EVENT_JSON:"; "") | fromjson | .data[0].request_data | fromjson | .request_id) + else (.receipts[0].receipt.receipt.Action.actions[0].FunctionCall.args + | @base64d | fromjson | .request_id) + end + ) + } + ]' +``` + +Обе строки несут `request_id: 1868`, подтверждая пару. Половина-запрос, подписанная `retrorn.near` в блоке `194832281`, лежит в логе `EVENT_JSON:` её receipt (это yield/resume-паттерн NEAR — on-chain-обещание приостанавливается, пока TDX-worker выполняется). Половина-worker приходит через 11 блоков с `submit_execution_output_and_resolve`, подписанной `worker.outlayer.near`, и её `request_id` достаётся прямо из base64-обёрнутых `FunctionCall.args`. Те же два payload несут и более богатый отпечаток — `sender_id`, `project_id`, `code_hash`, `resources_used.instructions`, `resources_used.time_ms`, размер зашифрованного результата в байтах — если нужно проверить, что именно исполнилось; этот минимальный pipeline лишь подтверждает, что половины принадлежат друг другу. `/v0/transactions` отдаёт исторические пары бессрочно, поэтому archival RPC для самой трассировки не нужен даже через недели. + +## Частые ошибки + +- Пытаться отправить транзакцию через history-API вместо raw RPC. +- Использовать Transactions API, когда пользователю нужны только текущие балансы или активы. +- Спускаться в raw RPC до того, как индексированная история ответила на читаемый вопрос «что произошло?». + +## Связанные страницы + +- [Transactions API](https://docs.fastnear.com/ru/tx) +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [FastNear API](https://docs.fastnear.com/ru/api) +- [NEAR Data API](https://docs.fastnear.com/ru/neardata) +- [Berry Club: живая доска и один путь исторической реконструкции](https://docs.fastnear.com/ru/tx/examples/berry-club) +- [Расширенный поиск записи SocialDB](https://docs.fastnear.com/ru/tx/socialdb-proofs) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/examples/berry-club.md b/static/ru/tx/examples/berry-club.md new file mode 100644 index 0000000..15427bf --- /dev/null +++ b/static/ru/tx/examples/berry-club.md @@ -0,0 +1,127 @@ +**Источник:** [https://docs.fastnear.com/ru/tx/examples/berry-club](https://docs.fastnear.com/ru/tx/examples/berry-club) + +{/* FASTNEAR_AI_DISCOVERY: Этот walkthrough показывает краткий и полезный путь для Berry Club: сначала прочитайте живую доску через RPC get_lines, а Transactions API используйте только тогда, когда нужно восстановить одну более раннюю эпоху по draw-вызовам. */} + +# Berry Club: как читать живую доску и разбирать одну эпоху + +Используйте этот walkthrough, когда живую доску читать легко, но нужен один понятный путь к исторической реконструкции. + +Начните с живой доски. Если этого уже достаточно для ответа, на этом можно остановиться. + +Переходите к Transactions API только тогда, когда вопрос становится историческим: «как Berry Club выглядел в одной более ранней эпохе и какие `draw`-вызовы сделали доску именно такой?» + +Эти shell-примеры работают и с публичными RPC и Transactions endpoint-ами. Если `FASTNEAR_API_KEY` уже задан в окружении, FastNear-вызовы автоматически пробросят его как bearer-заголовок. + +Карточка живой доски: запрашивает `berryclub.ek.near` `get_lines` через mainnet RPC и рендерит текущую сетку 50x50 в интерфейсе документации. + +## 1. Прочитайте живую доску + +Это самый короткий полезный запрос: + +```bash +ARGS_BASE64="$(jq -nc '{lines: [range(0;50)]}' | base64 | tr -d '\n')" +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "{ + \"jsonrpc\": \"2.0\", + \"id\": \"berry-live-board\", + \"method\": \"query\", + \"params\": { + \"request_type\": \"call_function\", + \"finality\": \"final\", + \"account_id\": \"berryclub.ek.near\", + \"method_name\": \"get_lines\", + \"args_base64\": \"$ARGS_BASE64\" + } + }" | jq '.result | {block_height, line_count: (.result | implode | fromjson | length)}' +``` + +Этот запрос отдаёт текущую доску 50x50 прямо из контракта. Дальше нужно только декодировать каждую base64-строку в 50 цветов пикселей. + +## 2. Восстановите одну более раннюю эпоху + +Когда нужна история, держите путь коротким: + +1. ограничьте одну эпоху +2. получите кандидатные `draw`-транзакции для `berryclub.ek.near` +3. раскройте эти хеши +4. проиграйте массивы `pixels` от старых к новым + +В этом примере используется узкое окно вокруг блока `97601515`: + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://tx.main.fastnear.com/v0/account \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{ + "account_id": "berryclub.ek.near", + "is_function_call": true, + "is_receiver": true, + "is_real_receiver": true, + "from_tx_block_height": 97576515, + "to_tx_block_height": 97601516, + "desc": false, + "limit": 200 + }' | jq '.account_txs | map({transaction_hash, tx_block_height}) | .[-5:]' +``` + +Если окно ещё нужно подобрать, сначала можно использовать [`/v0/blocks`](https://docs.fastnear.com/ru/tx/blocks). Это не часть основного Berry Club-сценария. + +Раскройте кандидатные хеши и оставьте только верхнеуровневые вызовы `draw`: + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://tx.main.fastnear.com/v0/transactions \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{ + "tx_hashes": [ + "Hq5qwsuiM2emJrqczWM9awCa7o6sTBYqYpcifUX2SUhQ", + "8tBip5M2TrozhSyepAA3tYXpyKooi5t7b9c64wXjFvfL" + ] + }' | jq '.transactions[] + | select(.transaction.receiver_id == "berryclub.ek.near") + | .transaction.actions[]?.FunctionCall + | select(.method_name == "draw") + | {method_name, args: (.args | @base64d | fromjson)}' +``` + +Затем проиграйте массивы `pixels` от старых к новым: + +```javascript +const board = Array.from({ length: 50 }, () => Array(50).fill(0)); + +for (const drawTx of drawTransactionsOldestFirst) { + for (const pixel of drawTx.args.pixels) { + if (pixel.x < 0 || pixel.x >= 50 || pixel.y < 0 || pixel.y >= 50) { + continue; + } + + board[pixel.y][pixel.x] = pixel.color; + } +} +``` + +В этом и состоит исторический паттерн. У Berry Club нет готового эндпоинта «доска на блоке N», поэтому старые эпохи восстанавливаются проигрыванием `draw`-записей. + +## Связанные руководства + +- [RPC: call_function](https://docs.fastnear.com/ru/rpc/contract/call-function) +- [Transactions API: история аккаунта](https://docs.fastnear.com/ru/tx/account) +- [Transactions API: транзакции по хешу](https://docs.fastnear.com/ru/tx/transactions) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/examples/berry-club/index.md b/static/ru/tx/examples/berry-club/index.md new file mode 100644 index 0000000..15427bf --- /dev/null +++ b/static/ru/tx/examples/berry-club/index.md @@ -0,0 +1,127 @@ +**Источник:** [https://docs.fastnear.com/ru/tx/examples/berry-club](https://docs.fastnear.com/ru/tx/examples/berry-club) + +{/* FASTNEAR_AI_DISCOVERY: Этот walkthrough показывает краткий и полезный путь для Berry Club: сначала прочитайте живую доску через RPC get_lines, а Transactions API используйте только тогда, когда нужно восстановить одну более раннюю эпоху по draw-вызовам. */} + +# Berry Club: как читать живую доску и разбирать одну эпоху + +Используйте этот walkthrough, когда живую доску читать легко, но нужен один понятный путь к исторической реконструкции. + +Начните с живой доски. Если этого уже достаточно для ответа, на этом можно остановиться. + +Переходите к Transactions API только тогда, когда вопрос становится историческим: «как Berry Club выглядел в одной более ранней эпохе и какие `draw`-вызовы сделали доску именно такой?» + +Эти shell-примеры работают и с публичными RPC и Transactions endpoint-ами. Если `FASTNEAR_API_KEY` уже задан в окружении, FastNear-вызовы автоматически пробросят его как bearer-заголовок. + +Карточка живой доски: запрашивает `berryclub.ek.near` `get_lines` через mainnet RPC и рендерит текущую сетку 50x50 в интерфейсе документации. + +## 1. Прочитайте живую доску + +Это самый короткий полезный запрос: + +```bash +ARGS_BASE64="$(jq -nc '{lines: [range(0;50)]}' | base64 | tr -d '\n')" +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://rpc.mainnet.fastnear.com \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "{ + \"jsonrpc\": \"2.0\", + \"id\": \"berry-live-board\", + \"method\": \"query\", + \"params\": { + \"request_type\": \"call_function\", + \"finality\": \"final\", + \"account_id\": \"berryclub.ek.near\", + \"method_name\": \"get_lines\", + \"args_base64\": \"$ARGS_BASE64\" + } + }" | jq '.result | {block_height, line_count: (.result | implode | fromjson | length)}' +``` + +Этот запрос отдаёт текущую доску 50x50 прямо из контракта. Дальше нужно только декодировать каждую base64-строку в 50 цветов пикселей. + +## 2. Восстановите одну более раннюю эпоху + +Когда нужна история, держите путь коротким: + +1. ограничьте одну эпоху +2. получите кандидатные `draw`-транзакции для `berryclub.ek.near` +3. раскройте эти хеши +4. проиграйте массивы `pixels` от старых к новым + +В этом примере используется узкое окно вокруг блока `97601515`: + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://tx.main.fastnear.com/v0/account \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{ + "account_id": "berryclub.ek.near", + "is_function_call": true, + "is_receiver": true, + "is_real_receiver": true, + "from_tx_block_height": 97576515, + "to_tx_block_height": 97601516, + "desc": false, + "limit": 200 + }' | jq '.account_txs | map({transaction_hash, tx_block_height}) | .[-5:]' +``` + +Если окно ещё нужно подобрать, сначала можно использовать [`/v0/blocks`](https://docs.fastnear.com/ru/tx/blocks). Это не часть основного Berry Club-сценария. + +Раскройте кандидатные хеши и оставьте только верхнеуровневые вызовы `draw`: + +```bash +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -sS https://tx.main.fastnear.com/v0/transactions \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data '{ + "tx_hashes": [ + "Hq5qwsuiM2emJrqczWM9awCa7o6sTBYqYpcifUX2SUhQ", + "8tBip5M2TrozhSyepAA3tYXpyKooi5t7b9c64wXjFvfL" + ] + }' | jq '.transactions[] + | select(.transaction.receiver_id == "berryclub.ek.near") + | .transaction.actions[]?.FunctionCall + | select(.method_name == "draw") + | {method_name, args: (.args | @base64d | fromjson)}' +``` + +Затем проиграйте массивы `pixels` от старых к новым: + +```javascript +const board = Array.from({ length: 50 }, () => Array(50).fill(0)); + +for (const drawTx of drawTransactionsOldestFirst) { + for (const pixel of drawTx.args.pixels) { + if (pixel.x < 0 || pixel.x >= 50 || pixel.y < 0 || pixel.y >= 50) { + continue; + } + + board[pixel.y][pixel.x] = pixel.color; + } +} +``` + +В этом и состоит исторический паттерн. У Berry Club нет готового эндпоинта «доска на блоке N», поэтому старые эпохи восстанавливаются проигрыванием `draw`-записей. + +## Связанные руководства + +- [RPC: call_function](https://docs.fastnear.com/ru/rpc/contract/call-function) +- [Transactions API: история аккаунта](https://docs.fastnear.com/ru/tx/account) +- [Transactions API: транзакции по хешу](https://docs.fastnear.com/ru/tx/transactions) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/examples/index.md b/static/ru/tx/examples/index.md new file mode 100644 index 0000000..6d7cfc9 --- /dev/null +++ b/static/ru/tx/examples/index.md @@ -0,0 +1,253 @@ +**Источник:** [https://docs.fastnear.com/ru/tx/examples](https://docs.fastnear.com/ru/tx/examples) + +## Начните здесь + +Все shell-примеры ниже работают на публичных Transactions API-хостах как есть. Если в shell задан `FASTNEAR_API_KEY`, они автоматически добавляют bearer header; если переменная не задана, они переходят на публичный неаутентифицированный путь. + +### У меня один хеш транзакции. Что произошло? + +Вставьте хеш в `POST /v0/transactions` — один ответ обычно содержит всю историю. + +```bash +TX_HASH=7ZKnhzt2MqMNmsk13dV8GAjGu3Db8aHzSBHeNeu9MJCq +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq '{ + hash: .transactions[0].transaction.hash, + signer_id: .transactions[0].transaction.signer_id, + receiver_id: .transactions[0].transaction.receiver_id, + included_block_height: .transactions[0].execution_outcome.block_height, + actions: (.transactions[0].transaction.actions | map(if type == "string" then . else keys[0] end)), + first_receipt_id: .transactions[0].execution_outcome.outcome.status.SuccessReceiptId, + receipt_count: (.transactions[0].receipts | length) + }' +``` + +Для зафиксированного хеша `root.near` отправил один `Transfer` на `escrow.ai.near` в блоке `188976785`, с передачей в receipt `B8QzHQZ6VnUVy8zaVXCEkWuSs7MPb34yoHYixZV3Zdj1`. Если `receipt_count > 1` или следующий вопрос касается поведения на уровне receipt, переходите к [Какой receipt испустил этот лог или событие?](#какой-receipt-испустил-этот-лог-или-событие) или [`POST /v0/receipt`](https://docs.fastnear.com/ru/tx/receipt). + +### Какой receipt испустил этот лог или событие? + +Выведите список всех receipt транзакции с логами и флагом, содержат ли их логи ваш фрагмент. Совпадение доказывается, а не угадывается: у зафиксированной транзакции один receipt логирует `Transfer`, другой — `Refund`, и только сторона `Refund` переключается в `true`. + +```bash +TX_HASH=2KhhB1uDScGCFQfVchep7DiZTGTxMcgfUYHNzwf5e6uL +LOG_FRAGMENT=Refund +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg fragment "$LOG_FRAGMENT" ' + [ + .transactions[0].receipts[] + | select((.execution_outcome.outcome.logs | length) > 0) + | { + receipt_id: .receipt.receipt_id, + receiver_id: .receipt.receiver_id, + method_name: (.receipt.receipt.Action.actions[0] + | if type == "string" then . else (.FunctionCall.method_name // keys[0]) end), + matches_fragment: any(.execution_outcome.outcome.logs[]?; contains($fragment)), + logs: .execution_outcome.outcome.logs + } + ]' +``` + +Фрагмент `Refund` атрибутируется receipt `9sLHQpaGz3NnMNMn8zGrDUSyktR1q6ts2otr9mHkfD1w` на `wrap.near`, метод `ft_resolve_transfer`. Логи receipt живут на receipts, а не на транзакции, поэтому одного прохода достаточно — более глубокая async-трассировка не нужна. + +### Превратить один receipt ID в читаемую историю транзакции {#receipt-id-to-readable-story} + +`POST /v0/receipt` возвращает запись receipt **и** его полную родительскую транзакцию в одном ответе, поэтому единственного запроса хватает на всю историю — дополнительный `/v0/transactions` не нужен. + +```bash +RECEIPT_ID=B8QzHQZ6VnUVy8zaVXCEkWuSs7MPb34yoHYixZV3Zdj1 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/receipt" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg receipt_id "$RECEIPT_ID" '{receipt_id: $receipt_id}')" \ + | jq '{ + receipt: { + receipt_id: .receipt.receipt_id, + type: .receipt.receipt_type, + is_success: .receipt.is_success, + receipt_block: .receipt.block_height, + tx_block: .receipt.tx_block_height, + predecessor_id: .receipt.predecessor_id, + receiver_id: .receipt.receiver_id, + transaction_hash: .receipt.transaction_hash + }, + parent_transaction: { + signer_id: .transaction.transaction.signer_id, + receiver_id: .transaction.transaction.receiver_id, + action_types: (.transaction.transaction.actions | map(if type == "string" then . else keys[0] end)) + } + }' +``` + +Для зафиксированного receipt это возвращает `Action`-receipt от `root.near` к `escrow.ai.near`, который успешно выполнился в блоке `188976786`, через один блок после попадания родительской транзакции `7ZKnhzt2…`, — один `Transfer` (3.5 NEAR, в сыром `.transaction.transaction.actions` видимо как `3500000000000000000000000` yocto). Если интересным якорем становится родительская транзакция, хеш у вас уже есть — переиспользуйте его в [У меня один хеш транзакции. Что произошло?](#у-меня-один-хеш-транзакции-что-произошло). + +## Сбои и async + +### Доказать, что один провалившийся action откатил весь batch + +Один batch отправил `CreateAccount → Transfer → AddKey → FunctionCall`, и финальный вызов попал в отсутствующий метод. Индексированная запись транзакции уже несёт упорядоченный batch *и* точный сбой на уровне receipt, поэтому одного запроса хватает, чтобы ответить «что пытались и что сломалось»; проверка через `view_account` затем доказывает, что предыдущие actions откатились. + +```bash +TX_HASH=CrhH3xLzbNwNMGgZkgptXorwh8YmqxRGuA6Mc11MkU6M +NEW_ACCOUNT_ID=rollback-mo4vmkig.temp.mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.test.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq '{ + action_types: (.transactions[0].transaction.actions | map(if type == "string" then . else keys[0] end)), + final_method: .transactions[0].transaction.actions[3].FunctionCall.method_name, + tx_handoff: .transactions[0].execution_outcome.outcome.status, + receipt_failure: ( + first( + .transactions[0].receipts[] + | select(.execution_outcome.outcome.status.Failure != null) + | .execution_outcome.outcome.status.Failure.ActionError + ) + ) + }' +``` + +Статус на уровне транзакции — `SuccessReceiptId`: транзакция успешно передала свои batched actions в receipt. Сбой лежит слоем ниже на этом receipt: `index: 3` (именно `FunctionCall`), вид `CodeDoesNotExist` на `rollback-mo4vmkig.temp.mike.testnet`. `SuccessReceiptId` в tx-outcome означает «handoff прошёл», а не «всё завершилось» — реальная ловушка, если смотреть только на статус уровня транзакции. + +Теперь докажите откат предыдущих actions: спросите аккаунт, который batch *пытался* создать: + +```bash +NEW_ACCOUNT_ID=rollback-mo4vmkig.temp.mike.testnet +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://rpc.testnet.fastnear.com" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$NEW_ACCOUNT_ID" '{ + jsonrpc: "2.0", id: "fastnear", method: "query", + params: {request_type: "view_account", account_id: $account_id, finality: "final"} + }')" \ + | jq '{error: .error.cause.name, requested_account_id: .error.cause.info.requested_account_id}' +``` + +`UNKNOWN_ACCOUNT` — это и есть доказательство. Если бы `CreateAccount` закрепился, `view_account` вернул бы результат; раз нет — предыдущие `Transfer` и `AddKey` из того же batched-receipt тоже не закрепились. + +### Когда транзакция выглядит успешной — что на самом деле произошло? + +Внешний `execution_outcome.outcome.status` рапортует `SuccessReceiptId`, как только сработал handoff первого receipt, — и ничего не говорит о том, успешны ли дочерние receipts и отработал ли callback на исходном контракте. Один pipeline над `/v0/transactions` отвечает сразу на все три вопроса. + +```bash +TX_HASH=2KhhB1uDScGCFQfVchep7DiZTGTxMcgfUYHNzwf5e6uL +ORIGIN_CONTRACT_ID=wrap.near +CALLBACK_METHOD=ft_resolve_transfer +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg origin "$ORIGIN_CONTRACT_ID" --arg callback "$CALLBACK_METHOD" '{ + outer: { + method: .transactions[0].transaction.actions[0].FunctionCall.method_name, + tx_handoff: (.transactions[0].execution_outcome.outcome.status | keys[0]) + }, + callback: { + expected_on: $origin, + method: $callback, + ran: any( + .transactions[0].receipts[]; + .receipt.receiver_id == $origin + and (.receipt.receipt.Action.actions[0].FunctionCall.method_name // "") == $callback + ) + }, + descendant_failures: [ + .transactions[0].receipts[] + | select(.execution_outcome.outcome.status.Failure != null) + | { + receiver_id: .receipt.receiver_id, + method: (.receipt.receipt.Action.actions[0].FunctionCall.method_name // "system"), + cause: .execution_outcome.outcome.status.Failure + } + ] + }' +``` + +Для зафиксированной транзакции `outer.method` — `ft_transfer_call`, а `outer.tx_handoff` — `SuccessReceiptId`: транзакция чисто запустила свой первый receipt, и если смотреть только сюда, можно назвать это победой. `descendant_failures` рассказывают вторую историю: `ft_on_transfer` на `v2.ref-finance.near` упал с `E51: contract paused` — DEX был на паузе во время этого свопа и не мог принять wrapped NEAR. `callback.ran: true` — третью: callback `ft_resolve_transfer` на `wrap.near` всё равно отработал. Сбой ниже по цепочке никогда не мешает callback исходного контракта — именно так NEP-141 возвращает отправителю средства, когда получатель их отклонил. + +Успех receipt не транзитивен. Протокол может чисто отдать handoff и при этом увидеть, как отцеплённая работа провалится позже; callback исходного контракта отработает в любом случае. Прочитайте эти три поля вместе — и async-история становится читаемой без ручного обхода цепочки receipts. Чтобы вытянуть сам лог `Refund`, переходите к [Какой receipt испустил этот лог или событие?](#какой-receipt-испустил-этот-лог-или-событие). + +### Сопоставить запрос OutLayer с его TEE-разрешением + +[OutLayer](https://outlayer.fastnear.com) разделяет один логический вызов на две транзакции: пользователь подписывает `request_execution` на `outlayer.near`, worker в Intel TDX запускает нужный WASM off-chain, затем `worker.outlayer.near` присылает результат через `submit_execution_output_and_resolve`. Обе половины несут один и тот же `request_id` — передайте оба tx-хеша в один запрос `/v0/transactions` и извлеките это поле с каждой стороны, чтобы подтвердить пару. + +```bash +REQUEST_TX=BZDQAxEdpQ9wUGXmXTa2APwFLDTTqTy5ucrBPsfgZeyz +WORKER_TX=3NYD4Mkn5cwkuVkGP9PPoiJ9PB5Vr7v6r8CwSswtHVA3 +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi + +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg a "$REQUEST_TX" --arg b "$WORKER_TX" '{tx_hashes: [$a, $b]}')" \ + | jq '[ + .transactions[] + | { + role: (if .transaction.actions[0].FunctionCall.method_name == "request_execution" + then "request" else "worker" end), + hash: .transaction.hash, + signer: .transaction.signer_id, + method: .transaction.actions[0].FunctionCall.method_name, + block: .execution_outcome.block_height, + request_id: ( + if .transaction.actions[0].FunctionCall.method_name == "request_execution" + then (.receipts[0].execution_outcome.outcome.logs[] | select(startswith("EVENT_JSON")) + | sub("EVENT_JSON:"; "") | fromjson | .data[0].request_data | fromjson | .request_id) + else (.receipts[0].receipt.receipt.Action.actions[0].FunctionCall.args + | @base64d | fromjson | .request_id) + end + ) + } + ]' +``` + +Обе строки несут `request_id: 1868`, подтверждая пару. Половина-запрос, подписанная `retrorn.near` в блоке `194832281`, лежит в логе `EVENT_JSON:` её receipt (это yield/resume-паттерн NEAR — on-chain-обещание приостанавливается, пока TDX-worker выполняется). Половина-worker приходит через 11 блоков с `submit_execution_output_and_resolve`, подписанной `worker.outlayer.near`, и её `request_id` достаётся прямо из base64-обёрнутых `FunctionCall.args`. Те же два payload несут и более богатый отпечаток — `sender_id`, `project_id`, `code_hash`, `resources_used.instructions`, `resources_used.time_ms`, размер зашифрованного результата в байтах — если нужно проверить, что именно исполнилось; этот минимальный pipeline лишь подтверждает, что половины принадлежат друг другу. `/v0/transactions` отдаёт исторические пары бессрочно, поэтому archival RPC для самой трассировки не нужен даже через недели. + +## Частые ошибки + +- Пытаться отправить транзакцию через history-API вместо raw RPC. +- Использовать Transactions API, когда пользователю нужны только текущие балансы или активы. +- Спускаться в raw RPC до того, как индексированная история ответила на читаемый вопрос «что произошло?». + +## Связанные страницы + +- [Transactions API](https://docs.fastnear.com/ru/tx) +- [RPC Reference](https://docs.fastnear.com/ru/rpc) +- [FastNear API](https://docs.fastnear.com/ru/api) +- [NEAR Data API](https://docs.fastnear.com/ru/neardata) +- [Berry Club: живая доска и один путь исторической реконструкции](https://docs.fastnear.com/ru/tx/examples/berry-club) +- [Расширенный поиск записи SocialDB](https://docs.fastnear.com/ru/tx/socialdb-proofs) +- [Choosing the Right Surface](https://docs.fastnear.com/ru/agents/choosing-surfaces) +- [Agent Playbooks](https://docs.fastnear.com/ru/agents/playbooks) +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/index.md b/static/ru/tx/index.md index bf3aadc..565c487 100644 --- a/static/ru/tx/index.md +++ b/static/ru/tx/index.md @@ -40,6 +40,10 @@ https://tx.test.fastnear.com - [Поиск квитанции](https://docs.fastnear.com/ru/tx/receipt) — для расследования цепочки исполнения. - [Диапазон блоков](https://docs.fastnear.com/ru/tx/blocks) — когда нужен ограниченный по диапазону просмотр истории. +## Нужен сценарий? + +Используйте [примеры API транзакций](https://docs.fastnear.com/ru/tx/examples) для практических примеров: поиска транзакций, расследования квитанций, истории аккаунта и анализа диапазонов блоков. + ## Устранение неполадок ### Я ожидал, что здесь можно отправлять транзакции @@ -53,3 +57,10 @@ https://tx.test.fastnear.com ### Мне нужен только один канонический результат статуса транзакции из RPC Используйте сырой RPC вместо индексированного семейства истории. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/receipt.md b/static/ru/tx/receipt.md index fe7d5a0..53ef0d2 100644 --- a/static/ru/tx/receipt.md +++ b/static/ru/tx/receipt.md @@ -235,3 +235,10 @@ "refName": "ReceiptResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/receipt/index.md b/static/ru/tx/receipt/index.md index fe7d5a0..53ef0d2 100644 --- a/static/ru/tx/receipt/index.md +++ b/static/ru/tx/receipt/index.md @@ -235,3 +235,10 @@ "refName": "ReceiptResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/socialdb-proofs.md b/static/ru/tx/socialdb-proofs.md new file mode 100644 index 0000000..1c32166 --- /dev/null +++ b/static/ru/tx/socialdb-proofs.md @@ -0,0 +1,162 @@ +**Источник:** [https://docs.fastnear.com/ru/tx/socialdb-proofs](https://docs.fastnear.com/ru/tx/socialdb-proofs) + +# Расширенный поиск записи SocialDB + +Используйте эту страницу только тогда, когда отправная точка — уже читаемое значение SocialDB из `api.near.social`, а следующий вопрос относится к историческому поиску записи. + +Эти shell-шаги работают и с публичными endpoint-ами SocialDB и FastNear. Если `FASTNEAR_API_KEY` уже задан в окружении, FastNear-вызовы автоматически пробросят его как bearer-заголовок. + +Для FastNear-first-задач сначала откройте [Transactions Examples](https://docs.fastnear.com/ru/tx/examples). Сюда переходите только тогда, когда вопрос звучит как «какая запись сделала это читаемое значение SocialDB истинным?». + +## Канонический пример: доказать, что `root.near` установил `profile.name` в `Illia` + +Используйте этот сценарий, когда читаемый факт уже звучит как «текущее `profile.name` равно `Illia`», а остаётся вопрос, какая запись сделала это поле истинным. + +Это единственный нюанс SocialDB, который стоит запомнить: для исторического доказательства правильным мостом обычно служит `:block` на уровне поля, а не `:block` родительского объекта. + +Для этого живого якоря: + +- текущее `profile.name`: `Illia` +- блок записи SocialDB на уровне поля: `75590392` +- receipt ID: `GYvnvBxWA46UGa3aGEkqUBeT7hxhVXk2iZScJFZWU8Se` +- хеш исходной транзакции: `7HtFWv51k5Bispmh1WYPbAVkxr2X4AL6n98DhcQwVw7w` +- внешний блок транзакции: `75590391` + +### Shell-сценарий + +1. Прочитайте поле из NEAR Social и сохраните блок записи на уровне поля. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name + +PROFILE="$(curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')")" + +echo "$PROFILE" | jq --arg account_id "$ACCOUNT_ID" '{ + current_name: .[$account_id].profile.name[""], + field_block_height: .[$account_id].profile.name[":block"], + parent_profile_block_height: .[$account_id].profile[":block"] +}' + +PROFILE_BLOCK_HEIGHT="$(echo "$PROFILE" | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]')" +``` + +2. Переиспользуйте этот блок уровня поля в FastNear block receipts и восстановите receipt вместе с tx hash. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +PROFILE_BLOCK_HEIGHT="$( + curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]' +)" +BLOCK_RECEIPTS="$(curl -s "https://tx.main.fastnear.com/v0/block" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --argjson block_id "$PROFILE_BLOCK_HEIGHT" '{ + block_id: $block_id, + with_transactions: false, + with_receipts: true + }')")" + +echo "$BLOCK_RECEIPTS" | jq --arg account_id "$ACCOUNT_ID" '{ + profile_receipt: ( + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | {receipt_id, transaction_hash, block_height, tx_block_height} + ) + ) +}' + +PROFILE_TX_HASH="$(echo "$BLOCK_RECEIPTS" | jq -r --arg account_id "$ACCOUNT_ID" ' + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | .transaction_hash + )')" +``` + +3. Переиспользуйте этот tx hash в `POST /v0/transactions` и декодируйте payload записи SocialDB. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +PROFILE_BLOCK_HEIGHT="$( + curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]' +)" +PROFILE_TX_HASH="$( + curl -s "https://tx.main.fastnear.com/v0/block" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --argjson block_id "$PROFILE_BLOCK_HEIGHT" '{ + block_id: $block_id, + with_transactions: false, + with_receipts: true + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" ' + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | .transaction_hash + )' +)" +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$PROFILE_TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg account_id "$ACCOUNT_ID" '{ + transaction: { + hash: .transactions[0].transaction.hash, + signer_id: .transactions[0].transaction.signer_id, + receiver_id: .transactions[0].transaction.receiver_id, + included_block_height: .transactions[0].execution_outcome.block_height + }, + write_proof: ( + .transactions[0].receipts[0].receipt.receipt.Action.actions[0].FunctionCall + | (.args | @base64d | fromjson | .data[$account_id].profile) as $profile + | { + method_name, + profile_name: $profile.name, + image_fields: (($profile.image // {}) | keys), + linktree_keys: (($profile.linktree // {}) | keys) + } + ) + }' +``` + +Это и есть весь паттерн lookup: читаемое значение, блок уровня поля, мост через receipt и payload транзакции. + +Тот же мост работает и для других читаемых значений SocialDB: + +- вариант для связи подписки: `root.near -> mob.near`, блок `79152039`, tx `DvNoqtDrruhmcq7mPpxdFacph2ZCqSzMFF5ZqMRFG78q` +- вариант для исходника виджета: `root.near/widget/Profile`, блок `76029540`, tx `ELS3DrE4Upoc91ZnBh4thVugxCUBAbaLFB4nyKsoyRNP` + +Ключевая идея не меняется: начните с читаемого значения и его write-block, восстановите receipt `*.near -> social.near` из блока, а затем декодируйте payload `social.near set` из исходной транзакции. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/socialdb-proofs/index.md b/static/ru/tx/socialdb-proofs/index.md new file mode 100644 index 0000000..1c32166 --- /dev/null +++ b/static/ru/tx/socialdb-proofs/index.md @@ -0,0 +1,162 @@ +**Источник:** [https://docs.fastnear.com/ru/tx/socialdb-proofs](https://docs.fastnear.com/ru/tx/socialdb-proofs) + +# Расширенный поиск записи SocialDB + +Используйте эту страницу только тогда, когда отправная точка — уже читаемое значение SocialDB из `api.near.social`, а следующий вопрос относится к историческому поиску записи. + +Эти shell-шаги работают и с публичными endpoint-ами SocialDB и FastNear. Если `FASTNEAR_API_KEY` уже задан в окружении, FastNear-вызовы автоматически пробросят его как bearer-заголовок. + +Для FastNear-first-задач сначала откройте [Transactions Examples](https://docs.fastnear.com/ru/tx/examples). Сюда переходите только тогда, когда вопрос звучит как «какая запись сделала это читаемое значение SocialDB истинным?». + +## Канонический пример: доказать, что `root.near` установил `profile.name` в `Illia` + +Используйте этот сценарий, когда читаемый факт уже звучит как «текущее `profile.name` равно `Illia`», а остаётся вопрос, какая запись сделала это поле истинным. + +Это единственный нюанс SocialDB, который стоит запомнить: для исторического доказательства правильным мостом обычно служит `:block` на уровне поля, а не `:block` родительского объекта. + +Для этого живого якоря: + +- текущее `profile.name`: `Illia` +- блок записи SocialDB на уровне поля: `75590392` +- receipt ID: `GYvnvBxWA46UGa3aGEkqUBeT7hxhVXk2iZScJFZWU8Se` +- хеш исходной транзакции: `7HtFWv51k5Bispmh1WYPbAVkxr2X4AL6n98DhcQwVw7w` +- внешний блок транзакции: `75590391` + +### Shell-сценарий + +1. Прочитайте поле из NEAR Social и сохраните блок записи на уровне поля. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name + +PROFILE="$(curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')")" + +echo "$PROFILE" | jq --arg account_id "$ACCOUNT_ID" '{ + current_name: .[$account_id].profile.name[""], + field_block_height: .[$account_id].profile.name[":block"], + parent_profile_block_height: .[$account_id].profile[":block"] +}' + +PROFILE_BLOCK_HEIGHT="$(echo "$PROFILE" | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]')" +``` + +2. Переиспользуйте этот блок уровня поля в FastNear block receipts и восстановите receipt вместе с tx hash. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +PROFILE_BLOCK_HEIGHT="$( + curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]' +)" +BLOCK_RECEIPTS="$(curl -s "https://tx.main.fastnear.com/v0/block" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --argjson block_id "$PROFILE_BLOCK_HEIGHT" '{ + block_id: $block_id, + with_transactions: false, + with_receipts: true + }')")" + +echo "$BLOCK_RECEIPTS" | jq --arg account_id "$ACCOUNT_ID" '{ + profile_receipt: ( + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | {receipt_id, transaction_hash, block_height, tx_block_height} + ) + ) +}' + +PROFILE_TX_HASH="$(echo "$BLOCK_RECEIPTS" | jq -r --arg account_id "$ACCOUNT_ID" ' + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | .transaction_hash + )')" +``` + +3. Переиспользуйте этот tx hash в `POST /v0/transactions` и декодируйте payload записи SocialDB. + +```bash +ACCOUNT_ID=root.near +PROFILE_FIELD=profile/name +AUTH_HEADER=() +if [ -n "${FASTNEAR_API_KEY:-}" ]; then AUTH_HEADER=(-H "Authorization: Bearer $FASTNEAR_API_KEY"); fi +PROFILE_BLOCK_HEIGHT="$( + curl -s "https://api.near.social/get" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg account_id "$ACCOUNT_ID" --arg profile_field "$PROFILE_FIELD" '{ + keys: [($account_id + "/" + $profile_field)], + options: {with_block_height: true} + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" '.[$account_id].profile.name[":block"]' +)" +PROFILE_TX_HASH="$( + curl -s "https://tx.main.fastnear.com/v0/block" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --argjson block_id "$PROFILE_BLOCK_HEIGHT" '{ + block_id: $block_id, + with_transactions: false, + with_receipts: true + }')" \ + | jq -r --arg account_id "$ACCOUNT_ID" ' + first( + .block_receipts[] + | select(.predecessor_id == $account_id and .receiver_id == "social.near") + | .transaction_hash + )' +)" +curl -s "https://tx.main.fastnear.com/v0/transactions" \ + "${AUTH_HEADER[@]}" \ + -H 'content-type: application/json' \ + --data "$(jq -nc --arg tx_hash "$PROFILE_TX_HASH" '{tx_hashes: [$tx_hash]}')" \ + | jq --arg account_id "$ACCOUNT_ID" '{ + transaction: { + hash: .transactions[0].transaction.hash, + signer_id: .transactions[0].transaction.signer_id, + receiver_id: .transactions[0].transaction.receiver_id, + included_block_height: .transactions[0].execution_outcome.block_height + }, + write_proof: ( + .transactions[0].receipts[0].receipt.receipt.Action.actions[0].FunctionCall + | (.args | @base64d | fromjson | .data[$account_id].profile) as $profile + | { + method_name, + profile_name: $profile.name, + image_fields: (($profile.image // {}) | keys), + linktree_keys: (($profile.linktree // {}) | keys) + } + ) + }' +``` + +Это и есть весь паттерн lookup: читаемое значение, блок уровня поля, мост через receipt и payload транзакции. + +Тот же мост работает и для других читаемых значений SocialDB: + +- вариант для связи подписки: `root.near -> mob.near`, блок `79152039`, tx `DvNoqtDrruhmcq7mPpxdFacph2ZCqSzMFF5ZqMRFG78q` +- вариант для исходника виджета: `root.near/widget/Profile`, блок `76029540`, tx `ELS3DrE4Upoc91ZnBh4thVugxCUBAbaLFB4nyKsoyRNP` + +Ключевая идея не меняется: начните с читаемого значения и его write-block, восстановите receipt `*.near -> social.near` из блока, а затем декодируйте payload `social.near set` из исходной транзакции. +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/transactions.md b/static/ru/tx/transactions.md index cee060f..efb5c58 100644 --- a/static/ru/tx/transactions.md +++ b/static/ru/tx/transactions.md @@ -98,3 +98,10 @@ "refName": "TransactionsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com). diff --git a/static/ru/tx/transactions/index.md b/static/ru/tx/transactions/index.md index cee060f..efb5c58 100644 --- a/static/ru/tx/transactions/index.md +++ b/static/ru/tx/transactions/index.md @@ -98,3 +98,10 @@ "refName": "TransactionsResponse" } ``` +--- +## О FastNear + +- FastNear обрабатывает более 10 млрд запросов в месяц. +- FastNear управляет более чем 100 нодами по всему миру. +- Один API-ключ FastNear работает и для RPC, и для индексированных API. +- Получите API-ключ на [dashboard.fastnear.com](https://dashboard.fastnear.com).