crypto-aio 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +151 -1
- package/README.md +32 -12
- package/dist/adapters/evm/builder.js +64 -4
- package/dist/adapters/evm/builder.js.map +1 -1
- package/dist/adapters/evm/decode.js +6 -1
- package/dist/adapters/evm/decode.js.map +1 -1
- package/dist/adapters/evm/ethers-client.js +4 -0
- package/dist/adapters/evm/ethers-client.js.map +1 -1
- package/dist/adapters/evm/fees.d.ts +24 -0
- package/dist/adapters/evm/fees.js +47 -4
- package/dist/adapters/evm/fees.js.map +1 -1
- package/dist/adapters/evm/index.d.ts +1 -1
- package/dist/adapters/evm/index.js +2 -1
- package/dist/adapters/evm/index.js.map +1 -1
- package/dist/adapters/evm/network.d.ts +5 -0
- package/dist/adapters/evm/network.js +21 -2
- package/dist/adapters/evm/network.js.map +1 -1
- package/dist/adapters/evm/plugin.d.ts +5 -6
- package/dist/adapters/evm/plugin.js +50 -2
- package/dist/adapters/evm/plugin.js.map +1 -1
- package/dist/adapters/evm/proofs.js +17 -5
- package/dist/adapters/evm/proofs.js.map +1 -1
- package/dist/adapters/evm/reader.d.ts +18 -0
- package/dist/adapters/evm/reader.js +34 -0
- package/dist/adapters/evm/reader.js.map +1 -1
- package/dist/adapters/evm/tokens.d.ts +3 -0
- package/dist/adapters/evm/tokens.js.map +1 -1
- package/dist/adapters/evm/types.d.ts +10 -0
- package/dist/adapters/evm/types.js.map +1 -1
- package/dist/adapters/evm/web3-client.d.ts +6 -3
- package/dist/adapters/evm/web3-client.js +19 -2
- package/dist/adapters/evm/web3-client.js.map +1 -1
- package/dist/adapters/solana/builder.js +29 -18
- package/dist/adapters/solana/builder.js.map +1 -1
- package/dist/adapters/solana/fees.d.ts +12 -3
- package/dist/adapters/solana/fees.js +13 -4
- package/dist/adapters/solana/fees.js.map +1 -1
- package/dist/adapters/solana/message.d.ts +15 -0
- package/dist/adapters/solana/message.js +120 -0
- package/dist/adapters/solana/message.js.map +1 -0
- package/dist/adapters/solana/plugin.js +4 -1
- package/dist/adapters/solana/plugin.js.map +1 -1
- package/dist/adapters/solana/types.d.ts +8 -5
- package/dist/adapters/solana/types.js.map +1 -1
- package/dist/adapters/solana/web3.js +10 -32
- package/dist/adapters/solana/web3.js.map +1 -1
- package/dist/adapters/ton/proofs.js +18 -76
- package/dist/adapters/ton/proofs.js.map +1 -1
- package/dist/adapters/ton/reader.d.ts +45 -4
- package/dist/adapters/ton/reader.js +200 -5
- package/dist/adapters/ton/reader.js.map +1 -1
- package/dist/adapters/ton/trace.d.ts +26 -0
- package/dist/adapters/ton/trace.js +35 -9
- package/dist/adapters/ton/trace.js.map +1 -1
- package/dist/adapters/tron/abi.d.ts +2 -0
- package/dist/adapters/tron/abi.js +2 -0
- package/dist/adapters/tron/abi.js.map +1 -1
- package/dist/adapters/tron/builder.js +20 -4
- package/dist/adapters/tron/builder.js.map +1 -1
- package/dist/adapters/tron/decode.d.ts +2 -0
- package/dist/adapters/tron/decode.js +1 -1
- package/dist/adapters/tron/decode.js.map +1 -1
- package/dist/adapters/tron/proofs.js +1 -0
- package/dist/adapters/tron/proofs.js.map +1 -1
- package/dist/adapters/tron/reader.d.ts +10 -0
- package/dist/adapters/tron/reader.js +17 -0
- package/dist/adapters/tron/reader.js.map +1 -1
- package/dist/adapters/tron/tokens.d.ts +2 -0
- package/dist/adapters/tron/tokens.js.map +1 -1
- package/dist/adapters/utxo/builder.js +1 -1
- package/dist/adapters/utxo/builder.js.map +1 -1
- package/dist/adapters/utxo/chains.js +2 -1
- package/dist/adapters/utxo/chains.js.map +1 -1
- package/dist/adapters/utxo/context.d.ts +6 -0
- package/dist/adapters/utxo/context.js +8 -1
- package/dist/adapters/utxo/context.js.map +1 -1
- package/dist/adapters/utxo/decode.d.ts +8 -0
- package/dist/adapters/utxo/decode.js +36 -0
- package/dist/adapters/utxo/decode.js.map +1 -1
- package/dist/adapters/utxo/driver.js +5 -0
- package/dist/adapters/utxo/driver.js.map +1 -1
- package/dist/adapters/utxo/esplora.d.ts +23 -2
- package/dist/adapters/utxo/esplora.js +49 -2
- package/dist/adapters/utxo/esplora.js.map +1 -1
- package/dist/adapters/utxo/proofs.d.ts +15 -6
- package/dist/adapters/utxo/proofs.js +185 -47
- package/dist/adapters/utxo/proofs.js.map +1 -1
- package/dist/adapters/utxo/rawblock.d.ts +46 -0
- package/dist/adapters/utxo/rawblock.js +159 -0
- package/dist/adapters/utxo/rawblock.js.map +1 -0
- package/dist/adapters/utxo/rawtx.d.ts +14 -0
- package/dist/adapters/utxo/rawtx.js +44 -14
- package/dist/adapters/utxo/rawtx.js.map +1 -1
- package/dist/core/blockchain/handle.d.ts +6 -27
- package/dist/core/blockchain/handle.js +112 -112
- package/dist/core/blockchain/handle.js.map +1 -1
- package/dist/core/config/types.d.ts +15 -0
- package/dist/core/config/types.js.map +1 -1
- package/dist/core/container/container.d.ts +1 -8
- package/dist/core/container/container.js +42 -8
- package/dist/core/container/container.js.map +1 -1
- package/dist/core/driver/types.d.ts +34 -1
- package/dist/core/driver/types.js.map +1 -1
- package/dist/core/errors/codes.d.ts +10 -0
- package/dist/core/errors/codes.js +4 -0
- package/dist/core/errors/codes.js.map +1 -1
- package/dist/core/lifecycle/engine-rules.d.ts +3 -4
- package/dist/core/lifecycle/engine-rules.js +16 -6
- package/dist/core/lifecycle/engine-rules.js.map +1 -1
- package/dist/core/lifecycle/engine.d.ts +2 -0
- package/dist/core/lifecycle/engine.js +19 -1
- package/dist/core/lifecycle/engine.js.map +1 -1
- package/dist/core/lifecycle/evaluate.js +9 -4
- package/dist/core/lifecycle/evaluate.js.map +1 -1
- package/dist/core/lifecycle/monitor.js +16 -6
- package/dist/core/lifecycle/monitor.js.map +1 -1
- package/dist/core/lifecycle/reconcile.d.ts +1 -1
- package/dist/core/lifecycle/reconcile.js +1 -1
- package/dist/core/lifecycle/reconcile.js.map +1 -1
- package/dist/core/lifecycle/workers.d.ts +9 -3
- package/dist/core/lifecycle/workers.js +32 -14
- package/dist/core/lifecycle/workers.js.map +1 -1
- package/dist/core/model/ids.d.ts +1 -0
- package/dist/core/model/ids.js +1 -0
- package/dist/core/model/ids.js.map +1 -1
- package/dist/core/model/ordering.d.ts +8 -0
- package/dist/core/model/ordering.js.map +1 -1
- package/dist/core/model/transaction.d.ts +7 -0
- package/dist/core/model/transaction.js.map +1 -1
- package/dist/core/observe/scanner.js +3 -0
- package/dist/core/observe/scanner.js.map +1 -1
- package/dist/core/signing/wallet.js +8 -0
- package/dist/core/signing/wallet.js.map +1 -1
- package/dist/core/store/format.d.ts +20 -0
- package/dist/core/store/format.js +86 -0
- package/dist/core/store/format.js.map +1 -0
- package/dist/core/store/memory.js +2 -2
- package/dist/core/store/memory.js.map +1 -1
- package/dist/core/store/types.d.ts +15 -3
- package/dist/core/store/types.js +2 -0
- package/dist/core/store/types.js.map +1 -1
- package/dist/core/transport/http-transport.js +21 -13
- package/dist/core/transport/http-transport.js.map +1 -1
- package/dist/core/transport/types.d.ts +16 -1
- package/dist/core/transport/types.js.map +1 -1
- package/dist/core/util/json.d.ts +7 -1
- package/dist/core/util/json.js +13 -4
- package/dist/core/util/json.js.map +1 -1
- package/dist/core/util/names.d.ts +6 -0
- package/dist/core/util/names.js +10 -0
- package/dist/core/util/names.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/testing/contracts/operations.js +20 -1
- package/dist/testing/contracts/operations.js.map +1 -1
- package/dist/testing/env.d.ts +5 -0
- package/dist/testing/env.js +1 -1
- package/dist/testing/env.js.map +1 -1
- package/dist/testing/faulty-store.d.ts +2 -0
- package/dist/testing/faulty-store.js +5 -0
- package/dist/testing/faulty-store.js.map +1 -1
- package/package.json +17 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fees.js","sourceRoot":"","sources":["../../../src/adapters/solana/fees.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Solana fee policy (base fee plus priority), pure and bigint-only. The\n * priority fee is `ceil(computeUnitPrice × computeUnitLimit / 1_000_000)` lamports, charged\n * on the requested limit (Solana's fee documentation).\n */\nimport { ValidationError } from '../../core/errors/error';\nimport type {\n FeeChargeDraft,\n FeeEstimateDraft,\n FeeOverride,\n FeeSpeed,\n} from '../../core/model/fee';\nimport { DEFAULT_INSTRUCTION_COMPUTE_UNITS, MAX_COMPUTE_UNIT_LIMIT } from './programs';\nimport { malformed, u64 } from './rpc';\nimport type { SolanaFeeDetails, SolanaFeeOverride } from './types';\n\n/** Library policy: the percentile of recent prioritization fees each speed pays. */\nexport const SPEED_PERCENTILE: Readonly<Record<FeeSpeed, number>> = Object.freeze({\n slow: 25,\n normal: 50,\n fast: 75,\n});\n\n/** Library policy: the compute-unit limit is the simulated usage plus 20% and 1,000 units. */\nexport function computeUnitLimitFor(unitsConsumed: bigint): bigint {\n const limit = unitsConsumed + unitsConsumed / 5n + 1_000n;\n return limit > MAX_COMPUTE_UNIT_LIMIT ? MAX_COMPUTE_UNIT_LIMIT : limit;\n}\n\n/** The runtime's own default when a simulation cannot measure the transaction. */\nexport function fallbackComputeUnitLimit(instructions: number): bigint {\n const limit = DEFAULT_INSTRUCTION_COMPUTE_UNITS * BigInt(instructions);\n return limit > MAX_COMPUTE_UNIT_LIMIT ? MAX_COMPUTE_UNIT_LIMIT : limit;\n}\n\n/**\n * Build variants: identical intents built on the same blockhash would\n * sign byte-identical messages, so a second Operation would silently share the first one's\n * signature and one payment would be lost. Each estimate therefore adds a variant to the\n * compute-unit limit (0 to 1,023 units) and, for a speed, to the price (0 to 999\n * micro-lamports): at most about one lamport of priority fee per 1,000 compute units.\n */\nexport const VARIANTS = 1_024 * 1_000;\n\nexport function variantOffsets(variant: number): {\n readonly limit: bigint;\n readonly price: bigint;\n} {\n return {\n limit: BigInt(variant % 1_024),\n price: BigInt(Math.floor(variant / 1_024) % 1_000),\n };\n}\n\n/** The largest price variant a speed adds, in micro-lamports per compute unit. */\nexport const MAX_PRICE_VARIANT = 999n;\n\n/**\n * A speed's signed price within the handle's `maxComputeUnitPrice`: the node's\n * percentile, at most the bound less the largest variant, plus this build's variant. The\n * signed price never exceeds the bound, and identical transfers still differ at it.\n * The bound is at least `MAX_PRICE_VARIANT` (`solanaNetworkConfig`).\n */\nexport function speedPrice(\n percentile: bigint,\n variant: bigint,\n maxComputeUnitPrice: bigint,\n): bigint {\n const ceiling = maxComputeUnitPrice - MAX_PRICE_VARIANT;\n return (percentile < ceiling ? percentile : ceiling) + variant;\n}\n\n/**\n * An explicit price above the handle's bound, refused before anything is signed. The details\n * carry the price and the bound (decimal strings), so the caller sees what to allow.\n */\nexport function aboveMaxPrice(\n price: bigint,\n maxComputeUnitPrice: bigint,\n): ValidationError {\n return new ValidationError(\n 'INVALID_INTENT',\n 'computeUnitPrice is above maxComputeUnitPrice, the Solana handle option that bounds it (micro-lamports per compute unit)',\n {\n details: {\n required: price.toString(),\n maxComputeUnitPrice: maxComputeUnitPrice.toString(),\n },\n },\n );\n}\n\n/**\n * The highest recent price a speed pays: the u64 range less the largest price variant\n * (999), so the varied price still fits its u64 field.\n */\nconst MAX_RECENT_PRICE = 2n ** 64n - 1n - 999n;\n\n/** A per-driver counter from a random start: distinct in-process, rare across processes. */\nexport function variantCounter(start: number): () => number {\n let next = start % VARIANTS;\n return () => {\n const variant = next;\n next = (next + 1) % VARIANTS;\n return variant;\n };\n}\n\nexport function priorityFee(computeUnitPrice: bigint, computeUnitLimit: bigint): bigint {\n return (computeUnitPrice * computeUnitLimit + 999_999n) / 1_000_000n;\n}\n\n/**\n * The nearest-rank percentile of `getRecentPrioritizationFees` answers (micro-lamports per\n * compute unit); `0n` when the node reports none. A malformed entry, including one outside\n * the u64 range or without room for the price variant, is a retryable\n * `PROVIDER_UNAVAILABLE`.\n */\nexport function priceForSpeed(recent: unknown, speed: FeeSpeed): bigint {\n if (!Array.isArray(recent)) throw malformed('getRecentPrioritizationFees');\n const fees = recent.map((entry: unknown) => {\n const fee = u64(\n (entry as { prioritizationFee?: unknown } | null)?.prioritizationFee,\n 'getRecentPrioritizationFees',\n );\n if (fee > MAX_RECENT_PRICE) throw malformed('getRecentPrioritizationFees');\n return fee;\n });\n if (fees.length === 0) return 0n;\n fees.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n const rank = Math.ceil((SPEED_PERCENTILE[speed] / 100) * fees.length);\n return fees[Math.max(0, rank - 1)] as bigint;\n}\n\n/** A validated `SolanaFeeOverride`; anything else is `INVALID_INTENT`. */\nexport function parseOverride(fee: FeeOverride): SolanaFeeOverride {\n const invalid = (reason: string) =>\n new ValidationError('INVALID_INTENT', `Solana fee override: ${reason}`);\n const keys = Object.keys(fee);\n if (keys.some((key) => key !== 'computeUnitPrice' && key !== 'computeUnitLimit')) {\n throw invalid('only computeUnitPrice and computeUnitLimit are allowed');\n }\n const { computeUnitPrice, computeUnitLimit } = fee;\n if (\n typeof computeUnitPrice !== 'bigint' ||\n computeUnitPrice < 0n ||\n computeUnitPrice >= 2n ** 64n\n ) {\n throw invalid('computeUnitPrice must be a bigint of micro-lamports in the u64 range');\n }\n if (\n computeUnitLimit !== undefined &&\n (typeof computeUnitLimit !== 'bigint' ||\n computeUnitLimit < 1n ||\n computeUnitLimit > MAX_COMPUTE_UNIT_LIMIT)\n ) {\n throw invalid('computeUnitLimit must be a bigint from 1 to 1,400,000');\n }\n return {\n computeUnitPrice,\n ...(computeUnitLimit !== undefined ? { computeUnitLimit } : {}),\n };\n}\n\n/**\n * The fee draft: `network` (the signature fee), `priority` and, when the recipient's token\n * account is created, `rent`. The bound is `exact` unless rent is charged: that deposit is\n * skipped when someone else creates the account first, so it is an upper bound.\n */\nexport function feeDraft(\n speed: FeeSpeed | 'custom',\n details: SolanaFeeDetails,\n): FeeEstimateDraft {\n const charges: FeeChargeDraft[] = [\n { asset: 'native', amount: details.baseFee, label: 'network' },\n { asset: 'native', amount: details.priorityFee, label: 'priority' },\n ];\n if (details.createsRecipientAccount) {\n charges.push({ asset: 'native', amount: details.rent, label: 'rent' });\n }\n return {\n kind: 'solana',\n speed,\n charges,\n bound: details.createsRecipientAccount ? 'upper' : 'exact',\n details: { ...details },\n };\n}\n\n/** The `SolanaFeeDetails` of a draft this driver made; anything else is `INVALID_INTENT`. */\nexport function detailsOf(fee: FeeEstimateDraft): SolanaFeeDetails {\n const d = fee.details as Partial<SolanaFeeDetails>;\n if (\n fee.kind !== 'solana' ||\n typeof d.computeUnitLimit !== 'bigint' ||\n typeof d.computeUnitPrice !== 'bigint' ||\n typeof d.baseFee !== 'bigint' ||\n typeof d.priorityFee !== 'bigint' ||\n typeof d.rent !== 'bigint' ||\n typeof d.signatures !== 'number' ||\n typeof d.createsRecipientAccount !== 'boolean'\n ) {\n throw new ValidationError('INVALID_INTENT', 'not a Solana fee estimate');\n }\n return {\n signatures: d.signatures,\n baseFee: d.baseFee,\n computeUnitLimit: d.computeUnitLimit,\n computeUnitPrice: d.computeUnitPrice,\n priorityFee: d.priorityFee,\n rent: d.rent,\n createsRecipientAccount: d.createsRecipientAccount,\n };\n}\n\n/**\n * The compute budget `build` signs, checked wherever the estimate\n * came from (the store, `prepareTransfer`, a caller): the price within the handle's bound,\n * the limit within the protocol's, and the priority fee exactly the one that budget costs.\n */\nexport function signedFee(\n fee: FeeEstimateDraft,\n maxComputeUnitPrice: bigint,\n): SolanaFeeDetails {\n const details = detailsOf(fee);\n const { computeUnitPrice: price, computeUnitLimit: limit } = details;\n if (price > maxComputeUnitPrice) throw aboveMaxPrice(price, maxComputeUnitPrice);\n if (\n price < 0n ||\n limit < 1n ||\n limit > MAX_COMPUTE_UNIT_LIMIT ||\n details.priorityFee !== priorityFee(price, limit)\n ) {\n throw new ValidationError(\n 'INVALID_INTENT',\n 'the fee estimate is not consistent with its own compute budget',\n );\n }\n return details;\n}\n\n/** The lamports every fee charge of `fee` adds up to. */\nexport const lamportsCharged = (fee: FeeEstimateDraft): bigint =>\n fee.charges.reduce((sum, charge) => sum + charge.amount, 0n);\n"]}
|
|
1
|
+
{"version":3,"file":"fees.js","sourceRoot":"","sources":["../../../src/adapters/solana/fees.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Solana fee policy (base fee plus priority), pure and bigint-only. The base fee is\n * `LAMPORTS_PER_SIGNATURE` per signature, and the priority fee is\n * `ceil(computeUnitPrice × computeUnitLimit / 1_000_000)` lamports, charged on the requested\n * limit (Solana's fee documentation; agave `get_prioritization_fee`).\n */\nimport { ValidationError } from '../../core/errors/error';\nimport type {\n FeeChargeDraft,\n FeeEstimateDraft,\n FeeOverride,\n FeeSpeed,\n} from '../../core/model/fee';\nimport { DEFAULT_INSTRUCTION_COMPUTE_UNITS, MAX_COMPUTE_UNIT_LIMIT } from './programs';\nimport { malformed, u64 } from './rpc';\nimport type { SolanaFeeDetails, SolanaFeeOverride } from './types';\n\n/**\n * The signature fee, in lamports per signature of a message: agave's `FeeStructure` rate,\n * which every bank charges since the fee-rate governor was retired (`get_fee_for_message`\n * reads the blockhash's recorded rate only to know the blockhash). agave's\n * `calculate_signature_fee` also counts precompile (ed25519, secp256k1, secp256r1)\n * signatures; a transfer carries none, so its base fee follows from its signers alone.\n */\nexport const LAMPORTS_PER_SIGNATURE = 5_000n;\n\n/** Library policy: the percentile of recent prioritization fees each speed pays. */\nexport const SPEED_PERCENTILE: Readonly<Record<FeeSpeed, number>> = Object.freeze({\n slow: 25,\n normal: 50,\n fast: 75,\n});\n\n/** Library policy: the compute-unit limit is the simulated usage plus 20% and 1,000 units. */\nexport function computeUnitLimitFor(unitsConsumed: bigint): bigint {\n const limit = unitsConsumed + unitsConsumed / 5n + 1_000n;\n return limit > MAX_COMPUTE_UNIT_LIMIT ? MAX_COMPUTE_UNIT_LIMIT : limit;\n}\n\n/** The runtime's own default when a simulation cannot measure the transaction. */\nexport function fallbackComputeUnitLimit(instructions: number): bigint {\n const limit = DEFAULT_INSTRUCTION_COMPUTE_UNITS * BigInt(instructions);\n return limit > MAX_COMPUTE_UNIT_LIMIT ? MAX_COMPUTE_UNIT_LIMIT : limit;\n}\n\n/**\n * Build variants: identical intents built on the same blockhash would\n * sign byte-identical messages, so a second Operation would silently share the first one's\n * signature and one payment would be lost. Each estimate therefore adds a variant to the\n * compute-unit limit (0 to 1,023 units) and, for a speed, to the price (0 to 999\n * micro-lamports): at most about one lamport of priority fee per 1,000 compute units.\n */\nexport const VARIANTS = 1_024 * 1_000;\n\nexport function variantOffsets(variant: number): {\n readonly limit: bigint;\n readonly price: bigint;\n} {\n return {\n limit: BigInt(variant % 1_024),\n price: BigInt(Math.floor(variant / 1_024) % 1_000),\n };\n}\n\n/** The largest price variant a speed adds, in micro-lamports per compute unit. */\nexport const MAX_PRICE_VARIANT = 999n;\n\n/**\n * A speed's signed price within the handle's `maxComputeUnitPrice`: the node's\n * percentile, at most the bound less the largest variant, plus this build's variant. The\n * signed price never exceeds the bound, and identical transfers still differ at it.\n * The bound is at least `MAX_PRICE_VARIANT` (`solanaNetworkConfig`).\n */\nexport function speedPrice(\n percentile: bigint,\n variant: bigint,\n maxComputeUnitPrice: bigint,\n): bigint {\n const ceiling = maxComputeUnitPrice - MAX_PRICE_VARIANT;\n return (percentile < ceiling ? percentile : ceiling) + variant;\n}\n\n/**\n * An explicit price above the handle's bound, refused before anything is signed. The details\n * carry the price and the bound (decimal strings), so the caller sees what to allow.\n */\nexport function aboveMaxPrice(\n price: bigint,\n maxComputeUnitPrice: bigint,\n): ValidationError {\n return new ValidationError(\n 'INVALID_INTENT',\n 'computeUnitPrice is above maxComputeUnitPrice, the Solana handle option that bounds it (micro-lamports per compute unit)',\n {\n details: {\n required: price.toString(),\n maxComputeUnitPrice: maxComputeUnitPrice.toString(),\n },\n },\n );\n}\n\n/**\n * The highest recent price a speed pays: the u64 range less the largest price variant\n * (999), so the varied price still fits its u64 field.\n */\nconst MAX_RECENT_PRICE = 2n ** 64n - 1n - 999n;\n\n/** A per-driver counter from a random start: distinct in-process, rare across processes. */\nexport function variantCounter(start: number): () => number {\n let next = start % VARIANTS;\n return () => {\n const variant = next;\n next = (next + 1) % VARIANTS;\n return variant;\n };\n}\n\nexport function priorityFee(computeUnitPrice: bigint, computeUnitLimit: bigint): bigint {\n return (computeUnitPrice * computeUnitLimit + 999_999n) / 1_000_000n;\n}\n\n/**\n * The nearest-rank percentile of `getRecentPrioritizationFees` answers (micro-lamports per\n * compute unit); `0n` when the node reports none. A malformed entry, including one outside\n * the u64 range or without room for the price variant, is a retryable\n * `PROVIDER_UNAVAILABLE`.\n */\nexport function priceForSpeed(recent: unknown, speed: FeeSpeed): bigint {\n if (!Array.isArray(recent)) throw malformed('getRecentPrioritizationFees');\n const fees = recent.map((entry: unknown) => {\n const fee = u64(\n (entry as { prioritizationFee?: unknown } | null)?.prioritizationFee,\n 'getRecentPrioritizationFees',\n );\n if (fee > MAX_RECENT_PRICE) throw malformed('getRecentPrioritizationFees');\n return fee;\n });\n if (fees.length === 0) return 0n;\n fees.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n const rank = Math.ceil((SPEED_PERCENTILE[speed] / 100) * fees.length);\n return fees[Math.max(0, rank - 1)] as bigint;\n}\n\n/** A validated `SolanaFeeOverride`; anything else is `INVALID_INTENT`. */\nexport function parseOverride(fee: FeeOverride): SolanaFeeOverride {\n const invalid = (reason: string) =>\n new ValidationError('INVALID_INTENT', `Solana fee override: ${reason}`);\n const keys = Object.keys(fee);\n if (keys.some((key) => key !== 'computeUnitPrice' && key !== 'computeUnitLimit')) {\n throw invalid('only computeUnitPrice and computeUnitLimit are allowed');\n }\n const { computeUnitPrice, computeUnitLimit } = fee;\n if (\n typeof computeUnitPrice !== 'bigint' ||\n computeUnitPrice < 0n ||\n computeUnitPrice >= 2n ** 64n\n ) {\n throw invalid('computeUnitPrice must be a bigint of micro-lamports in the u64 range');\n }\n if (\n computeUnitLimit !== undefined &&\n (typeof computeUnitLimit !== 'bigint' ||\n computeUnitLimit < 1n ||\n computeUnitLimit > MAX_COMPUTE_UNIT_LIMIT)\n ) {\n throw invalid('computeUnitLimit must be a bigint from 1 to 1,400,000');\n }\n return {\n computeUnitPrice,\n ...(computeUnitLimit !== undefined ? { computeUnitLimit } : {}),\n };\n}\n\n/**\n * The fee draft: `network` (the signature fee), `priority` and, when the recipient's token\n * account is created, `rent`. The bound is `exact` unless rent is charged: that deposit is\n * skipped when someone else creates the account first, so it is an upper bound.\n */\nexport function feeDraft(\n speed: FeeSpeed | 'custom',\n details: SolanaFeeDetails,\n): FeeEstimateDraft {\n const charges: FeeChargeDraft[] = [\n { asset: 'native', amount: details.baseFee, label: 'network' },\n { asset: 'native', amount: details.priorityFee, label: 'priority' },\n ];\n if (details.createsRecipientAccount) {\n charges.push({ asset: 'native', amount: details.rent, label: 'rent' });\n }\n return {\n kind: 'solana',\n speed,\n charges,\n bound: details.createsRecipientAccount ? 'upper' : 'exact',\n details: { ...details },\n };\n}\n\n/** The `SolanaFeeDetails` of a draft this driver made; anything else is `INVALID_INTENT`. */\nexport function detailsOf(fee: FeeEstimateDraft): SolanaFeeDetails {\n const d = fee.details as Partial<SolanaFeeDetails>;\n if (\n fee.kind !== 'solana' ||\n typeof d.computeUnitLimit !== 'bigint' ||\n typeof d.computeUnitPrice !== 'bigint' ||\n typeof d.baseFee !== 'bigint' ||\n typeof d.priorityFee !== 'bigint' ||\n typeof d.rent !== 'bigint' ||\n typeof d.signatures !== 'number' ||\n typeof d.createsRecipientAccount !== 'boolean'\n ) {\n throw new ValidationError('INVALID_INTENT', 'not a Solana fee estimate');\n }\n return {\n signatures: d.signatures,\n baseFee: d.baseFee,\n computeUnitLimit: d.computeUnitLimit,\n computeUnitPrice: d.computeUnitPrice,\n priorityFee: d.priorityFee,\n rent: d.rent,\n createsRecipientAccount: d.createsRecipientAccount,\n };\n}\n\n/**\n * The compute budget `build` signs, checked wherever the estimate\n * came from (the store, `prepareTransfer`, a caller): the price within the handle's bound,\n * the limit within the protocol's, and the priority fee exactly the one that budget costs.\n */\nexport function signedFee(\n fee: FeeEstimateDraft,\n maxComputeUnitPrice: bigint,\n): SolanaFeeDetails {\n const details = detailsOf(fee);\n const { computeUnitPrice: price, computeUnitLimit: limit } = details;\n if (price > maxComputeUnitPrice) throw aboveMaxPrice(price, maxComputeUnitPrice);\n if (\n price < 0n ||\n limit < 1n ||\n limit > MAX_COMPUTE_UNIT_LIMIT ||\n details.priorityFee !== priorityFee(price, limit)\n ) {\n throw new ValidationError(\n 'INVALID_INTENT',\n 'the fee estimate is not consistent with its own compute budget',\n );\n }\n return details;\n}\n\n/** The lamports every fee charge of `fee` adds up to. */\nexport const lamportsCharged = (fee: FeeEstimateDraft): bigint =>\n fee.charges.reduce((sum, charge) => sum + charge.amount, 0n);\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SolanaInstruction } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* `findProgramAddressSync`: the first bump from 255 down whose address is off the curve,
|
|
4
|
+
* so no private key can sign for it. A seed is at most 32 bytes, as the runtime requires.
|
|
5
|
+
*/
|
|
6
|
+
export declare function programAddress(seeds: readonly Uint8Array[], programId: string): string;
|
|
7
|
+
/** The associated token account of `owner` for `mint` (classic Token program). */
|
|
8
|
+
export declare function associatedTokenAddress(owner: string, mint: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* A legacy message by the Solana message rules, as `@solana/web3.js` compiles it: the
|
|
11
|
+
* payer first, then the signers (writable, then read-only) and the non-signers (writable,
|
|
12
|
+
* then read-only), each group in order of first appearance, an instruction's program id
|
|
13
|
+
* before its accounts; an account is a signer or writable when any use makes it one.
|
|
14
|
+
*/
|
|
15
|
+
export declare function compileLegacyMessage(payer: string, recentBlockhash: string, instructions: readonly SolanaInstruction[]): Uint8Array;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.programAddress = programAddress;
|
|
4
|
+
exports.associatedTokenAddress = associatedTokenAddress;
|
|
5
|
+
exports.compileLegacyMessage = compileLegacyMessage;
|
|
6
|
+
/**
|
|
7
|
+
* The two pieces of Solana's wire format the driver builds itself, SDK-free: a legacy
|
|
8
|
+
* message and a program-derived address. Both used to come from `@solana/web3.js`, whose
|
|
9
|
+
* 3.x line dropped the synchronous derivation and rebuilt its classes on Kit; owning them
|
|
10
|
+
* keeps every signed byte independent of the SDK version a user installs. `codec.test.ts`
|
|
11
|
+
* checks both against `@solana/web3.js` 1.99 and frozen vectors.
|
|
12
|
+
*/
|
|
13
|
+
const ed25519_1 = require("@noble/curves/ed25519");
|
|
14
|
+
const sha256_1 = require("@noble/hashes/sha256");
|
|
15
|
+
const base_1 = require("@scure/base");
|
|
16
|
+
const error_1 = require("../../core/errors/error");
|
|
17
|
+
const programs_1 = require("./programs");
|
|
18
|
+
const wire_1 = require("./wire");
|
|
19
|
+
const PDA_MARKER = new TextEncoder().encode('ProgramDerivedAddress');
|
|
20
|
+
/** A 32-byte public key from its base58 text; the inputs are already validated. */
|
|
21
|
+
function key(address) {
|
|
22
|
+
const bytes = base_1.base58.decode(address);
|
|
23
|
+
if (bytes.length !== 32) {
|
|
24
|
+
throw new error_1.ValidationError('INVALID_ADDRESS', 'a Solana key is 32 bytes');
|
|
25
|
+
}
|
|
26
|
+
return bytes;
|
|
27
|
+
}
|
|
28
|
+
/** Whether `bytes` is a point of the ed25519 curve, i.e. could have a private key. */
|
|
29
|
+
function onCurve(bytes) {
|
|
30
|
+
try {
|
|
31
|
+
ed25519_1.ed25519.ExtendedPoint.fromHex(bytes);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* `findProgramAddressSync`: the first bump from 255 down whose address is off the curve,
|
|
40
|
+
* so no private key can sign for it. A seed is at most 32 bytes, as the runtime requires.
|
|
41
|
+
*/
|
|
42
|
+
function programAddress(seeds, programId) {
|
|
43
|
+
const program = key(programId);
|
|
44
|
+
for (let bump = 255; bump >= 0; bump--) {
|
|
45
|
+
const hash = sha256_1.sha256
|
|
46
|
+
.create()
|
|
47
|
+
.update(Uint8Array.from(seeds.flatMap((seed) => [...seed])))
|
|
48
|
+
.update(Uint8Array.of(bump))
|
|
49
|
+
.update(program)
|
|
50
|
+
.update(PDA_MARKER)
|
|
51
|
+
.digest();
|
|
52
|
+
if (!onCurve(hash))
|
|
53
|
+
return base_1.base58.encode(hash);
|
|
54
|
+
}
|
|
55
|
+
// Each bump has a one-in-two chance; all 256 failing does not happen.
|
|
56
|
+
throw new error_1.ValidationError('INVALID_ADDRESS', 'no program address for these seeds');
|
|
57
|
+
}
|
|
58
|
+
/** The associated token account of `owner` for `mint` (classic Token program). */
|
|
59
|
+
function associatedTokenAddress(owner, mint) {
|
|
60
|
+
return programAddress([key(owner), key(programs_1.TOKEN_PROGRAM), key(mint)], programs_1.ASSOCIATED_TOKEN_PROGRAM);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A legacy message by the Solana message rules, as `@solana/web3.js` compiles it: the
|
|
64
|
+
* payer first, then the signers (writable, then read-only) and the non-signers (writable,
|
|
65
|
+
* then read-only), each group in order of first appearance, an instruction's program id
|
|
66
|
+
* before its accounts; an account is a signer or writable when any use makes it one.
|
|
67
|
+
*/
|
|
68
|
+
function compileLegacyMessage(payer, recentBlockhash, instructions) {
|
|
69
|
+
const meta = new Map();
|
|
70
|
+
const note = (address, signer, writable) => {
|
|
71
|
+
const seen = meta.get(address);
|
|
72
|
+
meta.set(address, {
|
|
73
|
+
signer: (seen?.signer ?? false) || signer,
|
|
74
|
+
writable: (seen?.writable ?? false) || writable,
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
note(payer, true, true);
|
|
78
|
+
for (const ix of instructions) {
|
|
79
|
+
note(ix.programId, false, false);
|
|
80
|
+
for (const account of ix.accounts)
|
|
81
|
+
note(account.address, account.signer, account.writable);
|
|
82
|
+
}
|
|
83
|
+
const entries = [...meta.entries()];
|
|
84
|
+
const group = (signer, writable) => entries
|
|
85
|
+
.filter(([, m]) => m.signer === signer && m.writable === writable)
|
|
86
|
+
.map(([address]) => address);
|
|
87
|
+
const writableSigners = group(true, true);
|
|
88
|
+
const readonlySigners = group(true, false);
|
|
89
|
+
const writableOthers = group(false, true);
|
|
90
|
+
const readonlyOthers = group(false, false);
|
|
91
|
+
const keys = [
|
|
92
|
+
...writableSigners,
|
|
93
|
+
...readonlySigners,
|
|
94
|
+
...writableOthers,
|
|
95
|
+
...readonlyOthers,
|
|
96
|
+
];
|
|
97
|
+
// Indices are single bytes in a legacy message.
|
|
98
|
+
if (keys.length > 256) {
|
|
99
|
+
throw new error_1.ValidationError('INVALID_INTENT', 'too many accounts for one message');
|
|
100
|
+
}
|
|
101
|
+
const index = new Map(keys.map((address, i) => [address, i]));
|
|
102
|
+
const parts = [
|
|
103
|
+
Uint8Array.of(writableSigners.length + readonlySigners.length, readonlySigners.length, readonlyOthers.length),
|
|
104
|
+
(0, wire_1.encodeLength)(keys.length),
|
|
105
|
+
...keys.map(key),
|
|
106
|
+
key(recentBlockhash),
|
|
107
|
+
(0, wire_1.encodeLength)(instructions.length),
|
|
108
|
+
];
|
|
109
|
+
for (const ix of instructions) {
|
|
110
|
+
parts.push(Uint8Array.of(index.get(ix.programId)), (0, wire_1.encodeLength)(ix.accounts.length), Uint8Array.from(ix.accounts.map((a) => index.get(a.address))), (0, wire_1.encodeLength)(ix.data.length), ix.data);
|
|
111
|
+
}
|
|
112
|
+
const out = new Uint8Array(parts.reduce((n, part) => n + part.length, 0));
|
|
113
|
+
let offset = 0;
|
|
114
|
+
for (const part of parts) {
|
|
115
|
+
out.set(part, offset);
|
|
116
|
+
offset += part.length;
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=message.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../../src/adapters/solana/message.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The two pieces of Solana's wire format the driver builds itself, SDK-free: a legacy\n * message and a program-derived address. Both used to come from `@solana/web3.js`, whose\n * 3.x line dropped the synchronous derivation and rebuilt its classes on Kit; owning them\n * keeps every signed byte independent of the SDK version a user installs. `codec.test.ts`\n * checks both against `@solana/web3.js` 1.99 and frozen vectors.\n */\nimport { ed25519 } from '@noble/curves/ed25519';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { base58 } from '@scure/base';\nimport { ValidationError } from '../../core/errors/error';\nimport { ASSOCIATED_TOKEN_PROGRAM, TOKEN_PROGRAM } from './programs';\nimport type { SolanaInstruction } from './types';\nimport { encodeLength } from './wire';\n\nconst PDA_MARKER = new TextEncoder().encode('ProgramDerivedAddress');\n\n/** A 32-byte public key from its base58 text; the inputs are already validated. */\nfunction key(address: string): Uint8Array {\n const bytes = base58.decode(address);\n if (bytes.length !== 32) {\n throw new ValidationError('INVALID_ADDRESS', 'a Solana key is 32 bytes');\n }\n return bytes;\n}\n\n/** Whether `bytes` is a point of the ed25519 curve, i.e. could have a private key. */\nfunction onCurve(bytes: Uint8Array): boolean {\n try {\n ed25519.ExtendedPoint.fromHex(bytes);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * `findProgramAddressSync`: the first bump from 255 down whose address is off the curve,\n * so no private key can sign for it. A seed is at most 32 bytes, as the runtime requires.\n */\nexport function programAddress(seeds: readonly Uint8Array[], programId: string): string {\n const program = key(programId);\n for (let bump = 255; bump >= 0; bump--) {\n const hash = sha256\n .create()\n .update(Uint8Array.from(seeds.flatMap((seed) => [...seed])))\n .update(Uint8Array.of(bump))\n .update(program)\n .update(PDA_MARKER)\n .digest();\n if (!onCurve(hash)) return base58.encode(hash);\n }\n // Each bump has a one-in-two chance; all 256 failing does not happen.\n throw new ValidationError('INVALID_ADDRESS', 'no program address for these seeds');\n}\n\n/** The associated token account of `owner` for `mint` (classic Token program). */\nexport function associatedTokenAddress(owner: string, mint: string): string {\n return programAddress(\n [key(owner), key(TOKEN_PROGRAM), key(mint)],\n ASSOCIATED_TOKEN_PROGRAM,\n );\n}\n\n/**\n * A legacy message by the Solana message rules, as `@solana/web3.js` compiles it: the\n * payer first, then the signers (writable, then read-only) and the non-signers (writable,\n * then read-only), each group in order of first appearance, an instruction's program id\n * before its accounts; an account is a signer or writable when any use makes it one.\n */\nexport function compileLegacyMessage(\n payer: string,\n recentBlockhash: string,\n instructions: readonly SolanaInstruction[],\n): Uint8Array {\n const meta = new Map<string, { signer: boolean; writable: boolean }>();\n const note = (address: string, signer: boolean, writable: boolean) => {\n const seen = meta.get(address);\n meta.set(address, {\n signer: (seen?.signer ?? false) || signer,\n writable: (seen?.writable ?? false) || writable,\n });\n };\n note(payer, true, true);\n for (const ix of instructions) {\n note(ix.programId, false, false);\n for (const account of ix.accounts)\n note(account.address, account.signer, account.writable);\n }\n const entries = [...meta.entries()];\n const group = (signer: boolean, writable: boolean) =>\n entries\n .filter(([, m]) => m.signer === signer && m.writable === writable)\n .map(([address]) => address);\n const writableSigners = group(true, true);\n const readonlySigners = group(true, false);\n const writableOthers = group(false, true);\n const readonlyOthers = group(false, false);\n const keys = [\n ...writableSigners,\n ...readonlySigners,\n ...writableOthers,\n ...readonlyOthers,\n ];\n // Indices are single bytes in a legacy message.\n if (keys.length > 256) {\n throw new ValidationError('INVALID_INTENT', 'too many accounts for one message');\n }\n const index = new Map(keys.map((address, i) => [address, i]));\n const parts: Uint8Array[] = [\n Uint8Array.of(\n writableSigners.length + readonlySigners.length,\n readonlySigners.length,\n readonlyOthers.length,\n ),\n encodeLength(keys.length),\n ...keys.map(key),\n key(recentBlockhash),\n encodeLength(instructions.length),\n ];\n for (const ix of instructions) {\n parts.push(\n Uint8Array.of(index.get(ix.programId) as number),\n encodeLength(ix.accounts.length),\n Uint8Array.from(ix.accounts.map((a) => index.get(a.address) as number)),\n encodeLength(ix.data.length),\n ix.data,\n );\n }\n const out = new Uint8Array(parts.reduce((n, part) => n + part.length, 0));\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n return out;\n}\n"]}
|
|
@@ -8,7 +8,10 @@ const presets_1 = require("./presets");
|
|
|
8
8
|
const tokens_1 = require("./tokens");
|
|
9
9
|
/** The SDK versions this adapter is validated against, keyed by library. */
|
|
10
10
|
exports.SOLANA_PEER_DEPENDENCIES = Object.freeze({
|
|
11
|
-
'@solana/web3.js': Object.freeze({
|
|
11
|
+
'@solana/web3.js': Object.freeze({
|
|
12
|
+
name: '@solana/web3.js',
|
|
13
|
+
range: '^1.99.0 || ^3.0.0',
|
|
14
|
+
}),
|
|
12
15
|
});
|
|
13
16
|
/**
|
|
14
17
|
* The `@solana/web3.js` manifest, built once, at module level, like the presets. Plugins
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/adapters/solana/plugin.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/adapters/solana/plugin.ts"],"names":[],"mappings":";;;AA8CA,oCAQC;AA3CD,qCAAwC;AACxC,uCAAgD;AAChD,uCAA2C;AAC3C,qCAAyC;AAEzC,4EAA4E;AAC/D,QAAA,wBAAwB,GAEjC,MAAM,CAAC,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAAC;QAC/B,IAAI,EAAE,iBAAiB;QACvB,KAAK,EAAE,mBAAmB;KAC3B,CAAC;CACH,CAAC,CAAC;AAEH;;;;;GAKG;AACU,QAAA,cAAc,GAAoB,MAAM,CAAC,MAAM,CAAC;IAC3D,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,iBAAiB;IAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC;IACjC,YAAY,EAAE,6BAAmB;IACjC,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,gCAAwB,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC9E,IAAI,EAAE,KAAK,IAA4B,EAAE;QACvC,iEAAiE;QACjE,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAA4B,CAAC;QACzD,OAAO,GAAG,CAAC,iBAAiB,CAAC;IAC/B,CAAC;CACF,CAAC,CAAC;AAEH,+DAA+D;AAC/D,SAAgB,YAAY;IAC1B,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,CAAC,qBAAY,CAAC;QACtB,QAAQ,EAAE,CAAC,sBAAc,CAAC;QAC1B,OAAO,EAAE,wBAAc;QACvB,MAAM,EAAE,sBAAa;KACtB,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The Solana family plugin: the chain, tokens and provider presets as data, plus\n * one adapter manifest. SDK-free: only the manifest's `load()` requires the `@solana/web3.js`\n * module, and with it the SDK.\n */\nimport type {\n AdapterManifest,\n DriverFactory,\n PeerDependency,\n} from '../../core/driver/types';\nimport type { Plugin } from '../../core/registry/plugin';\nimport { SOLANA_CHAIN } from './chains';\nimport { SOLANA_CAPABILITIES } from './network';\nimport { SOLANA_PRESETS } from './presets';\nimport { SOLANA_TOKENS } from './tokens';\n\n/** The SDK versions this adapter is validated against, keyed by library. */\nexport const SOLANA_PEER_DEPENDENCIES: Readonly<\n Record<'@solana/web3.js', PeerDependency>\n> = Object.freeze({\n '@solana/web3.js': Object.freeze({\n name: '@solana/web3.js',\n range: '^1.99.0 || ^3.0.0',\n }),\n});\n\n/**\n * The `@solana/web3.js` manifest, built once, at module level, like the presets. Plugins\n * compare functions by identity, so every `solanaPlugin()` carries the same `load`\n * function and registering it again is the same plugin, not a conflicting one\n * (`CONFIG_INVALID`).\n */\nexport const solanaManifest: AdapterManifest = Object.freeze({\n family: 'solana',\n library: '@solana/web3.js',\n chains: Object.freeze(['solana']),\n capabilities: SOLANA_CAPABILITIES,\n peerDependencies: Object.freeze([SOLANA_PEER_DEPENDENCIES['@solana/web3.js']]),\n load: async (): Promise<DriverFactory> => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mod = require('./web3') as typeof import('./web3');\n return mod.web3DriverFactory;\n },\n});\n\n/** The built-in Solana family: mainnet, devnet and testnet. */\nexport function solanaPlugin(): Plugin {\n return {\n name: 'solana',\n chains: [SOLANA_CHAIN],\n adapters: [solanaManifest],\n presets: SOLANA_PRESETS,\n assets: SOLANA_TOKENS,\n };\n}\n"]}
|
|
@@ -47,7 +47,11 @@ export interface SolanaExt {
|
|
|
47
47
|
*/
|
|
48
48
|
export interface SolanaFeeDetails {
|
|
49
49
|
readonly signatures: number;
|
|
50
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* The signature fee: 5,000 lamports per signature of the message. The endpoint's
|
|
52
|
+
* `getFeeForMessage` quote must be exactly this plus `priorityFee`; any other quote fails
|
|
53
|
+
* the estimate with a retryable `PROVIDER_UNAVAILABLE`.
|
|
54
|
+
*/
|
|
51
55
|
readonly baseFee: bigint;
|
|
52
56
|
readonly computeUnitLimit: bigint;
|
|
53
57
|
/** Micro-lamports per compute unit. */
|
|
@@ -106,10 +110,9 @@ export interface SolanaInstruction {
|
|
|
106
110
|
readonly data: Uint8Array;
|
|
107
111
|
}
|
|
108
112
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* only.
|
|
113
|
+
* Program-derived addresses, legacy message compilation (both SDK-free, `message.ts`) and
|
|
114
|
+
* the native client. Inputs are already-validated canonical base58 keys; outputs are plain
|
|
115
|
+
* bytes and strings, never SDK objects, since store records hold plain data only.
|
|
113
116
|
*/
|
|
114
117
|
export interface SolanaCodec {
|
|
115
118
|
/** The associated token account of `owner` for `mint` (classic Token program). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/adapters/solana/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * SDK-free types of the Solana family: the `ext.solana` API, fee details and overrides, and\n * the narrow `SolanaCodec` that the `@solana/web3.js` module implements. Nothing\n * here imports an SDK, so the composition root can export these types.\n */\nimport type { DisposableNativeClient } from '../../core/driver/types';\nimport type { CallOptions } from '../../core/transport/types';\n\n// Augment the registries through the package entry, as users do with 'crypto-aio'.\ndeclare module '../../index' {\n interface ChainRegistry {\n solana: { family: 'solana'; network: 'mainnet' | 'devnet' | 'testnet' };\n }\n interface FamilyRegistry {\n solana: { library: '@solana/web3.js'; ext: SolanaExt; fee: SolanaFeeDetails };\n }\n}\n\n/** One SPL token account (classic Token program) of an owner. */\nexport interface SolanaTokenAccount {\n /** The token account's own address (an associated token account or any other). */\n readonly address: string;\n readonly mint: string;\n /** Base units of the mint. */\n readonly amount: bigint;\n readonly frozen: boolean;\n}\n\n/** `bc.ext.solana`: the Solana family extension. */\nexport interface SolanaExt {\n readonly solana: {\n /**\n * The owner's classic SPL token accounts, optionally for one mint, at the `confirmed`\n * commitment. Token-2022 accounts are not listed (Token-2022 is unsupported).\n */\n getTokenAccounts(\n owner: string,\n mint?: string,\n ): Promise<readonly SolanaTokenAccount[]>;\n };\n}\n\n/**\n * `FeeEstimate.details` of the `solana` fee kind (lamports; compute-unit price in\n * micro-lamports). The charges are `network` (the signature fee), `priority`\n * (`ceil(computeUnitPrice × computeUnitLimit / 1_000_000)`) and, when the recipient's\n * associated token account is created, `rent`.\n */\nexport interface SolanaFeeDetails {\n readonly signatures: number;\n
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/adapters/solana/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * SDK-free types of the Solana family: the `ext.solana` API, fee details and overrides, and\n * the narrow `SolanaCodec` that the `@solana/web3.js` module implements. Nothing\n * here imports an SDK, so the composition root can export these types.\n */\nimport type { DisposableNativeClient } from '../../core/driver/types';\nimport type { CallOptions } from '../../core/transport/types';\n\n// Augment the registries through the package entry, as users do with 'crypto-aio'.\ndeclare module '../../index' {\n interface ChainRegistry {\n solana: { family: 'solana'; network: 'mainnet' | 'devnet' | 'testnet' };\n }\n interface FamilyRegistry {\n solana: { library: '@solana/web3.js'; ext: SolanaExt; fee: SolanaFeeDetails };\n }\n}\n\n/** One SPL token account (classic Token program) of an owner. */\nexport interface SolanaTokenAccount {\n /** The token account's own address (an associated token account or any other). */\n readonly address: string;\n readonly mint: string;\n /** Base units of the mint. */\n readonly amount: bigint;\n readonly frozen: boolean;\n}\n\n/** `bc.ext.solana`: the Solana family extension. */\nexport interface SolanaExt {\n readonly solana: {\n /**\n * The owner's classic SPL token accounts, optionally for one mint, at the `confirmed`\n * commitment. Token-2022 accounts are not listed (Token-2022 is unsupported).\n */\n getTokenAccounts(\n owner: string,\n mint?: string,\n ): Promise<readonly SolanaTokenAccount[]>;\n };\n}\n\n/**\n * `FeeEstimate.details` of the `solana` fee kind (lamports; compute-unit price in\n * micro-lamports). The charges are `network` (the signature fee), `priority`\n * (`ceil(computeUnitPrice × computeUnitLimit / 1_000_000)`) and, when the recipient's\n * associated token account is created, `rent`.\n */\nexport interface SolanaFeeDetails {\n readonly signatures: number;\n /**\n * The signature fee: 5,000 lamports per signature of the message. The endpoint's\n * `getFeeForMessage` quote must be exactly this plus `priorityFee`; any other quote fails\n * the estimate with a retryable `PROVIDER_UNAVAILABLE`.\n */\n readonly baseFee: bigint;\n readonly computeUnitLimit: bigint;\n /** Micro-lamports per compute unit. */\n readonly computeUnitPrice: bigint;\n readonly priorityFee: bigint;\n /** The rent-exempt deposit of a created associated token account; `0n` otherwise. */\n readonly rent: bigint;\n /** Whether the transaction creates the recipient's associated token account. */\n readonly createsRecipientAccount: boolean;\n}\n\n/**\n * An explicit Solana fee (`TransferIntent.fee`): the compute-unit price in micro-lamports\n * (at most the handle's `maxComputeUnitPrice`) and, optionally, the compute-unit limit (1 to\n * 1,400,000), which otherwise comes from a simulation of the transaction. A type alias, not\n * an interface, so a value of this type is assignable to the core's `FeeOverride` record.\n */\nexport type SolanaFeeOverride = {\n readonly computeUnitPrice: bigint;\n readonly computeUnitLimit?: bigint;\n};\n\n/**\n * The transport tags every Solana I/O call carries: purpose, retry, quorum, fanout, signal,\n * and optionally the caller's own `quorumKey`, which replaces the method's\n * default consensus key.\n */\nexport type SolanaCallTags = Pick<\n CallOptions,\n 'purpose' | 'retry' | 'quorum' | 'quorumKey' | 'fanout' | 'signal'\n>;\n\nexport type Commitment = 'confirmed' | 'finalized';\n\n/**\n * The expiry ordering a Solana build records: the recent blockhash's\n * `lastValidBlockHeight`, the blockhash itself and the slot of its block, all from one\n * `getLatestBlockhash` answer, so one endpoint's word. A verdict rests on the height the\n * proof quorum attests for `blockhash` instead: the finalized block at\n * `blockhashSlot`, when it carries the blockhash, gives the last valid height as its own\n * height plus 150 (agave's `MAX_PROCESSING_AGE`); otherwise the finalized block 150 below\n * `lastValidHeight` must carry it. No endpoint proposes the height: trusting the recorded\n * one would let an endpoint that reported it too low prove the transfer expired while it\n * can still land, and `rebuild` would pay twice. For the same reason a store must keep\n * this ordering whole and unmodified: a changed `blockhash` misplaces the window.\n */\nexport interface SolanaExpiryOrdering {\n readonly kind: 'expiry';\n readonly lastValidHeight: bigint;\n /** The message's recent blockhash (base58). */\n readonly blockhash: string;\n /** The slot of the block whose hash `blockhash` is. */\n readonly blockhashSlot: bigint;\n}\n\n/** One instruction of a transaction we build: program, accounts and data. */\nexport interface SolanaInstruction {\n readonly programId: string;\n readonly accounts: readonly {\n readonly address: string;\n readonly signer: boolean;\n readonly writable: boolean;\n }[];\n readonly data: Uint8Array;\n}\n\n/**\n * Program-derived addresses, legacy message compilation (both SDK-free, `message.ts`) and\n * the native client. Inputs are already-validated canonical base58 keys; outputs are plain\n * bytes and strings, never SDK objects, since store records hold plain data only.\n */\nexport interface SolanaCodec {\n /** The associated token account of `owner` for `mint` (classic Token program). */\n associatedTokenAddress(owner: string, mint: string): string;\n /** The legacy message bytes: header, account keys, recent blockhash, instructions. */\n compileMessage(\n payer: string,\n recentBlockhash: string,\n instructions: readonly SolanaInstruction[],\n ): Uint8Array;\n /** A fresh `Connection` on the same transport, for `crypto-aio/native`. */\n createNative(): DisposableNativeClient;\n}\n"]}
|
|
@@ -3,19 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.web3DriverFactory = void 0;
|
|
4
4
|
exports.createWeb3Codec = createWeb3Codec;
|
|
5
5
|
/**
|
|
6
|
-
* The only module that imports `@solana/web3.js
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* The only module that imports `@solana/web3.js`, for the `crypto-aio/native`
|
|
7
|
+
* `Connection` alone: the driver builds messages and program-derived addresses itself
|
|
8
|
+
* (`message.ts`), so it works the same with every supported SDK line (1.x and the
|
|
9
|
+
* Kit-based 3.x). It is never on a driver request path: `Connection` retries HTTP 429 on
|
|
10
|
+
* a real timer and would drop the call's tags, so the driver sends every request straight
|
|
11
|
+
* to the transport, and the native `Connection` reaches the same transport through
|
|
12
|
+
* `transport.createFetch`.
|
|
11
13
|
*/
|
|
12
14
|
const web3_js_1 = require("@solana/web3.js");
|
|
13
15
|
const types_1 = require("../../core/transport/types");
|
|
14
16
|
const driver_1 = require("./driver");
|
|
15
|
-
const
|
|
17
|
+
const message_1 = require("./message");
|
|
16
18
|
const rpc_1 = require("./rpc");
|
|
17
|
-
const TOKEN = new web3_js_1.PublicKey(programs_1.TOKEN_PROGRAM);
|
|
18
|
-
const ASSOCIATED_TOKEN = new web3_js_1.PublicKey(programs_1.ASSOCIATED_TOKEN_PROGRAM);
|
|
19
19
|
/**
|
|
20
20
|
* The tags of a native client's requests: broadcasts for its writes (a transaction send
|
|
21
21
|
* and a faucet airdrop, neither safe to retry as a read), plain reads for the rest.
|
|
@@ -28,30 +28,8 @@ function classify(_url, init) {
|
|
|
28
28
|
}
|
|
29
29
|
function createWeb3Codec(transport) {
|
|
30
30
|
return {
|
|
31
|
-
associatedTokenAddress
|
|
32
|
-
|
|
33
|
-
new web3_js_1.PublicKey(owner).toBuffer(),
|
|
34
|
-
TOKEN.toBuffer(),
|
|
35
|
-
new web3_js_1.PublicKey(mint).toBuffer(),
|
|
36
|
-
], ASSOCIATED_TOKEN);
|
|
37
|
-
return address.toBase58();
|
|
38
|
-
},
|
|
39
|
-
compileMessage(payer, recentBlockhash, instructions) {
|
|
40
|
-
const message = new web3_js_1.TransactionMessage({
|
|
41
|
-
payerKey: new web3_js_1.PublicKey(payer),
|
|
42
|
-
recentBlockhash,
|
|
43
|
-
instructions: instructions.map((ix) => new web3_js_1.TransactionInstruction({
|
|
44
|
-
programId: new web3_js_1.PublicKey(ix.programId),
|
|
45
|
-
keys: ix.accounts.map((a) => ({
|
|
46
|
-
pubkey: new web3_js_1.PublicKey(a.address),
|
|
47
|
-
isSigner: a.signer,
|
|
48
|
-
isWritable: a.writable,
|
|
49
|
-
})),
|
|
50
|
-
data: Buffer.from(ix.data),
|
|
51
|
-
})),
|
|
52
|
-
}).compileToLegacyMessage();
|
|
53
|
-
return new Uint8Array(message.serialize());
|
|
54
|
-
},
|
|
31
|
+
associatedTokenAddress: message_1.associatedTokenAddress,
|
|
32
|
+
compileMessage: message_1.compileLegacyMessage,
|
|
55
33
|
createNative() {
|
|
56
34
|
const connection = new web3_js_1.Connection(`${types_1.PLACEHOLDER_ORIGIN}/`, {
|
|
57
35
|
commitment: 'confirmed',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web3.js","sourceRoot":"","sources":["../../../src/adapters/solana/web3.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"web3.js","sourceRoot":"","sources":["../../../src/adapters/solana/web3.ts"],"names":[],"mappings":";;;AA2BA,0CAoCC;AA/DD;;;;;;;;GAQG;AACH,6CAA6C;AAC7C,sDAAgF;AAChF,qCAA+C;AAC/C,uCAAyE;AACzE,+BAAwC;AAGxC;;;GAGG;AACH,SAAS,QAAQ,CAAC,IAAS,EAAE,IAA6B;IACxD,MAAM,IAAI,GAAG,OAAO,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,OAAO,qDAAqD,CAAC,IAAI,CAAC,IAAI,CAAC;QACrE,CAAC,CAAC,eAAS;QACX,CAAC,CAAC,UAAI,CAAC;AACX,CAAC;AAED,SAAgB,eAAe,CAAC,SAAoB;IAClD,OAAO;QACL,sBAAsB,EAAtB,gCAAsB;QACtB,cAAc,EAAE,8BAAoB;QACpC,YAAY;YACV,MAAM,UAAU,GAAG,IAAI,oBAAU,CAAC,GAAG,0BAAkB,GAAG,EAAE;gBAC1D,UAAU,EAAE,WAAW;gBACvB,KAAK,EAAE,SAAS,CAAC,WAAW,CAAC,QAAQ,CAAC;gBACtC,SAAS,EAAE,KAAK;gBAChB,uBAAuB,EAAE,IAAI;aAC9B,CAAC,CAAC;YACH,OAAO;gBACL,MAAM,EAAE,UAAU;gBAClB,KAAK,EAAE,GAAG,EAAE;oBACV,gFAAgF;oBAChF,+EAA+E;oBAC/E,+EAA+E;oBAC/E,6EAA6E;oBAC7E,oCAAoC;oBACpC,MAAM,MAAM,GACV,UAOD,CAAC,aAAa,CAAC;oBAChB,IAAI,CAAC,MAAM;wBAAE,OAAO;oBACpB,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;oBAC/B,YAAY,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;oBACxC,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,CAAC;aACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,0FAA0F;AAC7E,QAAA,iBAAiB,GAAG,IAAA,4BAAmB,EAAC,eAAe,CAAC,CAAC","sourcesContent":["/**\n * The only module that imports `@solana/web3.js`, for the `crypto-aio/native`\n * `Connection` alone: the driver builds messages and program-derived addresses itself\n * (`message.ts`), so it works the same with every supported SDK line (1.x and the\n * Kit-based 3.x). It is never on a driver request path: `Connection` retries HTTP 429 on\n * a real timer and would drop the call's tags, so the driver sends every request straight\n * to the transport, and the native `Connection` reaches the same transport through\n * `transport.createFetch`.\n */\nimport { Connection } from '@solana/web3.js';\nimport { PLACEHOLDER_ORIGIN, type Transport } from '../../core/transport/types';\nimport { solanaDriverFactory } from './driver';\nimport { associatedTokenAddress, compileLegacyMessage } from './message';\nimport { BROADCAST, READ } from './rpc';\nimport type { SolanaCodec } from './types';\n\n/**\n * The tags of a native client's requests: broadcasts for its writes (a transaction send\n * and a faucet airdrop, neither safe to retry as a read), plain reads for the rest.\n */\nfunction classify(_url: URL, init: RequestInit | undefined) {\n const body = typeof init?.body === 'string' ? init.body : '';\n return /\"method\"\\s*:\\s*\"(?:sendTransaction|requestAirdrop)\"/.test(body)\n ? BROADCAST\n : READ;\n}\n\nexport function createWeb3Codec(transport: Transport): SolanaCodec {\n return {\n associatedTokenAddress,\n compileMessage: compileLegacyMessage,\n createNative() {\n const connection = new Connection(`${PLACEHOLDER_ORIGIN}/`, {\n commitment: 'confirmed',\n fetch: transport.createFetch(classify),\n httpAgent: false,\n disableRetryOnRateLimit: true,\n });\n return {\n client: connection,\n close: () => {\n // Subscriptions have no transport bridge, so a socket client that was used only\n // ever fails against the placeholder host and retries on a timer. Turn retries\n // off (a flag: it does not cancel a retry already armed), cancel the armed one\n // (while it waits there is no socket, so `close()` alone does nothing), then\n // close the socket if there is one.\n const socket = (\n connection as unknown as {\n _rpcWebSocket?: {\n close(): void;\n setAutoReconnect(on: boolean): void;\n reconnect_timer_id?: ReturnType<typeof setTimeout>;\n };\n }\n )._rpcWebSocket;\n if (!socket) return;\n socket.setAutoReconnect(false);\n clearTimeout(socket.reconnect_timer_id);\n socket.close();\n },\n };\n },\n };\n}\n\n/** The `@solana/web3.js` adapter's driver factory; the manifest's `load()` returns it. */\nexport const web3DriverFactory = solanaDriverFactory(createWeb3Codec);\n"]}
|
|
@@ -6,28 +6,6 @@ exports.expiredAt = expiredAt;
|
|
|
6
6
|
exports.replayVerdict = replayVerdict;
|
|
7
7
|
exports.createTonProofs = createTonProofs;
|
|
8
8
|
exports.createTonHistory = createTonHistory;
|
|
9
|
-
/**
|
|
10
|
-
* Proofs and address history. Every proof attests a fact at its own height, with a
|
|
11
|
-
* monotone predicate or at a fixed block, and no endpoint proposes a height. The one
|
|
12
|
-
* exception is the unanchored head: one endpoint's masterchain head, trailed by
|
|
13
|
-
* `finalitySkewBlocks` and attested by a quorum read of that block, retried at the
|
|
14
|
-
* transport's own lag tolerance. Every lookup is bound to what it asked for: a header
|
|
15
|
-
* names the block asked, the shard tops cover the basechain, a state and a get-method
|
|
16
|
-
* name the block asked and the state read there.
|
|
17
|
-
*
|
|
18
|
-
* "Not included" rests only on authenticated chain data, never on an indexer's records: a
|
|
19
|
-
* lying or lagging indexer can miss a message that ran, and a `rebuild` on its word would
|
|
20
|
-
* pay twice. The proof reads, at an attested block where the message is expired, the
|
|
21
|
-
* account's own chain of transactions, as the liteserver serves their cells, each hashed
|
|
22
|
-
* here and linked by its `prev_trans` fields back from the attested state's last
|
|
23
|
-
* transaction. A wallet can be reset (deleted, or destroyed to uninitialized, then
|
|
24
|
-
* re-deployed from its public `StateInit` with seqno 0), so an activation, a destruction
|
|
25
|
-
* or a chain start inside what the proof must see decides nothing, unless the chain
|
|
26
|
-
* itself shows our transaction. Anything not yet decidable throws a retryable
|
|
27
|
-
* `PROVIDER_UNAVAILABLE`, and an answer the chain could not have produced a retryable
|
|
28
|
-
* `PROVIDER_INCONSISTENT`; both decide nothing.
|
|
29
|
-
*/
|
|
30
|
-
const core_1 = require("@ton/core");
|
|
31
9
|
const error_1 = require("../../core/errors/error");
|
|
32
10
|
const api_1 = require("./api");
|
|
33
11
|
const messages_1 = require("./messages");
|
|
@@ -252,34 +230,6 @@ async function consumerOf(ctx, from, seqno, head, state) {
|
|
|
252
230
|
}
|
|
253
231
|
// ---- the account's own chain --------------------------------------------------------------
|
|
254
232
|
const hex256 = (value) => value.toString(16).padStart(64, '0');
|
|
255
|
-
/**
|
|
256
|
-
* A transaction the liteserver served, authenticated: its cell (capped by the API before
|
|
257
|
-
* this decodes it) hashes to the id expected, and it is the account's own at the lt
|
|
258
|
-
* expected. Anything else is not the chain's.
|
|
259
|
-
*/
|
|
260
|
-
const notTheChains = () => inconsistent("the liteserver answered a transaction that is not the chain's");
|
|
261
|
-
function authenticated(row, expected, account) {
|
|
262
|
-
if (row.lt !== expected.lt || row.hash !== expected.hash)
|
|
263
|
-
throw notTheChains();
|
|
264
|
-
let cell;
|
|
265
|
-
let tx;
|
|
266
|
-
try {
|
|
267
|
-
const cells = core_1.Cell.fromBoc(Buffer.from(row.boc, 'base64'));
|
|
268
|
-
if (cells.length !== 1)
|
|
269
|
-
throw notTheChains();
|
|
270
|
-
cell = cells[0];
|
|
271
|
-
tx = (0, core_1.loadTransaction)(cell.beginParse());
|
|
272
|
-
}
|
|
273
|
-
catch {
|
|
274
|
-
throw notTheChains();
|
|
275
|
-
}
|
|
276
|
-
if (cell.hash().toString('hex') !== expected.hash ||
|
|
277
|
-
tx.lt !== expected.lt ||
|
|
278
|
-
tx.address !== account) {
|
|
279
|
-
throw notTheChains();
|
|
280
|
-
}
|
|
281
|
-
return tx;
|
|
282
|
-
}
|
|
283
233
|
/** The most transactions one walk visits, fetched or kept: `WALK_PAGES` full pages. */
|
|
284
234
|
const WALK_LIMIT = exports.WALK_PAGES * WALK_PAGE;
|
|
285
235
|
/**
|
|
@@ -292,7 +242,7 @@ const WALK_LIMIT = exports.WALK_PAGES * WALK_PAGE;
|
|
|
292
242
|
* the chain it has not seen; a kept one is bound to the account as a fetched one is.
|
|
293
243
|
*/
|
|
294
244
|
async function walkChain(ctx, wallet, from, visit) {
|
|
295
|
-
const account =
|
|
245
|
+
const account = (0, reader_1.accountId)(wallet);
|
|
296
246
|
let expected = from;
|
|
297
247
|
let page = [];
|
|
298
248
|
let fetched = 0;
|
|
@@ -302,7 +252,7 @@ async function walkChain(ctx, wallet, from, visit) {
|
|
|
302
252
|
let tx = ctx.chainTxs.get(key);
|
|
303
253
|
if (tx !== undefined) {
|
|
304
254
|
if (tx.address !== account)
|
|
305
|
-
throw notTheChains();
|
|
255
|
+
throw (0, reader_1.notTheChains)();
|
|
306
256
|
// The page fetched earlier no longer follows the walk: drop it.
|
|
307
257
|
if (row !== undefined && (row.lt !== expected.lt || row.hash !== expected.hash)) {
|
|
308
258
|
page = [];
|
|
@@ -320,7 +270,7 @@ async function walkChain(ctx, wallet, from, visit) {
|
|
|
320
270
|
throw undecided('the liteserver does not hold the transaction asked');
|
|
321
271
|
}
|
|
322
272
|
}
|
|
323
|
-
tx = authenticated(next, expected, account);
|
|
273
|
+
tx = (0, reader_1.authenticated)(next, expected, account);
|
|
324
274
|
// Only a wallet-sized transaction is kept (a lying endpoint's is not): the memo
|
|
325
275
|
// stays bounded.
|
|
326
276
|
if (next.boc.length <= reader_1.MEMO_TX_LENGTH)
|
|
@@ -346,7 +296,7 @@ function phasesOf(tx) {
|
|
|
346
296
|
* activates the account (transaction.cpp). */
|
|
347
297
|
ran: vm !== undefined,
|
|
348
298
|
/** A request ran to the end, so a seqno moved (the action phase keeps it). */
|
|
349
|
-
consumed:
|
|
299
|
+
consumed: (0, reader_1.chainRan)(tx),
|
|
350
300
|
/** The account had code before or after. */
|
|
351
301
|
lived: CODE.has(tx.oldStatus) || CODE.has(tx.endStatus),
|
|
352
302
|
/** A re-deploy from no code: the seqno starts again (transaction.cpp activation). */
|
|
@@ -471,7 +421,7 @@ async function fromTheChain(ctx, q) {
|
|
|
471
421
|
first = tx.lt;
|
|
472
422
|
const t = phasesOf(tx);
|
|
473
423
|
const inbound = tx.inMessage;
|
|
474
|
-
if (ourRun(tx,
|
|
424
|
+
if ((0, reader_1.ourRun)(tx, q.wallet, q.id)) {
|
|
475
425
|
ours = hash;
|
|
476
426
|
return true;
|
|
477
427
|
}
|
|
@@ -508,16 +458,6 @@ async function fromTheChain(ctx, q) {
|
|
|
508
458
|
await codeNeverRan(ctx, q.wallet, q.head.id.seqno, first);
|
|
509
459
|
return { absent: true };
|
|
510
460
|
}
|
|
511
|
-
/**
|
|
512
|
-
* Whether `tx` is our message run to the end: its inbound external message's TEP-467 hash,
|
|
513
|
-
* computed here from the authenticated body, is `id`, and it consumed its seqno.
|
|
514
|
-
*/
|
|
515
|
-
function ourRun(tx, t, wallet, id) {
|
|
516
|
-
const inbound = tx.inMessage;
|
|
517
|
-
return (t.consumed &&
|
|
518
|
-
inbound?.info.type === 'external-in' &&
|
|
519
|
-
(0, wallets_1.externalHashOf)(wallet, inbound.body) === id);
|
|
520
|
-
}
|
|
521
461
|
/**
|
|
522
462
|
* The monotone predicate "my seqno is above `seqno`" at the endpoints' own states, under the
|
|
523
463
|
* proof quorum; its key is the verdict itself and never throws.
|
|
@@ -603,7 +543,7 @@ async function replayVerdict(ctx, message) {
|
|
|
603
543
|
linked = tx.lt === link.lastLt;
|
|
604
544
|
}
|
|
605
545
|
const t = phasesOf(tx);
|
|
606
|
-
if (ourRun(tx,
|
|
546
|
+
if ((0, reader_1.ourRun)(tx, wallet, id)) {
|
|
607
547
|
ours = true;
|
|
608
548
|
return true;
|
|
609
549
|
}
|
|
@@ -632,11 +572,12 @@ async function replayVerdict(ctx, message) {
|
|
|
632
572
|
return 'send';
|
|
633
573
|
}
|
|
634
574
|
/**
|
|
635
|
-
* Our indexed transaction that consumed its seqno, proven: a complete
|
|
636
|
-
* block the endpoints attest they hold, and the verdict, its jetton
|
|
637
|
-
* that block
|
|
575
|
+
* Our indexed transaction that consumed its seqno (the Attempt `id`), proven: a complete
|
|
576
|
+
* trace, whose last block the endpoints attest they hold, and the verdict, its jetton
|
|
577
|
+
* wallets confirmed at that block and a bounce read from the chain itself, both under the
|
|
578
|
+
* proof quorum.
|
|
638
579
|
*/
|
|
639
|
-
async function proveIncluded(ctx, tx, from) {
|
|
580
|
+
async function proveIncluded(ctx, tx, from, id) {
|
|
640
581
|
const trace = await ctx.api.trace(tx.hash, api_1.PROOF);
|
|
641
582
|
if (!trace || !trace.complete)
|
|
642
583
|
throw undecided('the message trace is not complete yet');
|
|
@@ -644,7 +585,7 @@ async function proveIncluded(ctx, tx, from) {
|
|
|
644
585
|
if (!(await ctx.api.reachedMasterchain(last, api_1.PROOF))) {
|
|
645
586
|
throw undecided('the endpoints have not reached the trace yet');
|
|
646
587
|
}
|
|
647
|
-
const verdict = await (0, reader_1.confirmLegs)(ctx, (0, trace_1.attemptVerdict)(tx, trace), from, api_1.PROOF, last);
|
|
588
|
+
const verdict = await (0, reader_1.confirmBounce)(ctx, await (0, reader_1.confirmLegs)(ctx, (0, trace_1.attemptVerdict)(tx, trace), from, api_1.PROOF, last), from, id, api_1.PROOF);
|
|
648
589
|
if (verdict.kind === 'pending')
|
|
649
590
|
throw undecided('the message trace is not complete yet');
|
|
650
591
|
const header = await masterchainBlock(ctx, tx.mcSeqno);
|
|
@@ -655,6 +596,7 @@ async function proveIncluded(ctx, tx, from) {
|
|
|
655
596
|
blockHash: header.id.rootHash,
|
|
656
597
|
txHash: tx.hash,
|
|
657
598
|
...(verdict.kind === 'failed' ? { reason: verdict.reason } : {}),
|
|
599
|
+
...(verdict.kind === 'failed' && verdict.failure ? { failure: verdict.failure } : {}),
|
|
658
600
|
};
|
|
659
601
|
}
|
|
660
602
|
/**
|
|
@@ -668,7 +610,7 @@ async function proveOurs(ctx, hash, wallet, id) {
|
|
|
668
610
|
if (!(0, trace_1.isOwnAttempt)(record, wallet, id) || !(0, trace_1.consumesSeqno)(record)) {
|
|
669
611
|
throw inconsistent("the indexer's record is not the chain's transaction");
|
|
670
612
|
}
|
|
671
|
-
return proveIncluded(ctx, record, wallet);
|
|
613
|
+
return proveIncluded(ctx, record, wallet, id);
|
|
672
614
|
}
|
|
673
615
|
const seqnoOrdering = (ordering) => ordering.kind === 'seqno' ? ordering : undefined;
|
|
674
616
|
function createTonProofs(ctx) {
|
|
@@ -688,12 +630,12 @@ function createTonProofs(ctx) {
|
|
|
688
630
|
// Only our own wallet transaction, its hash computed here from the bound body. A
|
|
689
631
|
// run that did not consume its seqno (a failed action phase) moved nothing and may
|
|
690
632
|
// run again until the message expires: only the seqno decides it.
|
|
691
|
-
const own = await (0, reader_1.findOwnAttempt)(ctx, ref, wallet, api_1.PROOF);
|
|
692
|
-
if (own && (0, trace_1.consumesSeqno)(own))
|
|
693
|
-
return proveIncluded(ctx, own, wallet);
|
|
694
633
|
const id = attemptId(ref.id);
|
|
695
634
|
if (id === undefined)
|
|
696
635
|
throw undecided('a TON attempt needs its message hash');
|
|
636
|
+
const own = await (0, reader_1.findOwnAttempt)(ctx, ref, wallet, api_1.PROOF);
|
|
637
|
+
if (own && (0, trace_1.consumesSeqno)(own))
|
|
638
|
+
return proveIncluded(ctx, own, wallet, id);
|
|
697
639
|
const slot = seqnoOrdering(ordering);
|
|
698
640
|
if (!slot)
|
|
699
641
|
throw undecided('a TON attempt needs its seqno ordering');
|
|
@@ -726,7 +668,7 @@ function createTonProofs(ctx) {
|
|
|
726
668
|
});
|
|
727
669
|
}
|
|
728
670
|
if (hint && (0, trace_1.isOwnAttempt)(hint, wallet, id))
|
|
729
|
-
return proveIncluded(ctx, hint, wallet);
|
|
671
|
+
return proveIncluded(ctx, hint, wallet, id);
|
|
730
672
|
}
|
|
731
673
|
// Never "not included" while the message may still run: a reset of the wallet could
|
|
732
674
|
// bring its seqno back to ours.
|