import type { Blockchain, SandboxContract, SendMessageResult, TreasuryContract } from '@ton/sandbox'; import { Address } from '@ton/core'; import { type AtlasFixture } from '@titon-network/atlas-sdk/testing'; import { Phoebe, type PhoebeConfigReply, type PhoebeInitConfig, type PriceLeaf } from '../contracts/Phoebe'; import { PhoebeMerkleTree } from '../merkle'; export interface DeployPhoebeFixtureOpts { /** * Initial `blockchain.now`. Defaults to `2_000_000_000` (≈ 2033-05-18). * Must be set before any treasury is created — time can't roll backwards. */ now?: number; /** * When true (default), Phoebe is admitted at Atlas and AutomatonSynced * for the solo operator — ready to accept PushSnapshot / RequestPrice * immediately. Set to false to exercise those bootstrap steps manually. */ autoBootstrap?: boolean; /** * Initial funding for the Phoebe contract. Default is 1 TON (generous). * Override if you're testing reserve edge cases. */ phoebeFunding?: bigint; /** * Optional tunable overrides — forwarded to `Phoebe.createFromConfig`. */ tunables?: PhoebeInitConfig['tunables']; } export interface FulfillPriceResult { /** Raw send result so you can `expect(...).toHaveTransaction(...)`. */ result: SendMessageResult; /** queryId used by the request. */ queryId: bigint; /** The leaf that was claimed in the proof. */ leaf: PriceLeaf; } export interface PhoebeFixture { /** The deployed Phoebe contract, opened through the sandbox. */ phoebe: SandboxContract; /** The full Atlas fixture (re-exposes atlas, owner, forgeton, automaton, groupSk/Pk, rotate, …). */ atlasFixture: AtlasFixture; /** Phoebe owner treasury — use `phoebeOwner.getSender()` for owner-gated messages. */ phoebeOwner: SandboxContract; /** Mock-ForgeTON treasury (shared with the Atlas fixture — same seed). */ forgeton: SandboxContract; /** * Solo operator treasury — both the sole pkShare holder (via atlas * fixture) and the one who pushes signed snapshots to Phoebe. * Identical address to `atlasFixture.automaton`. */ operator: SandboxContract; /** 32-byte BLS12-381 secret key — the solo group key. Re-exposed from atlas fixture. */ groupSk: Uint8Array; /** 48-byte compressed G1 group public key. Re-exposed from atlas fixture. */ groupPk: Uint8Array; /** * Mirror an operator from mock-ForgeTON into Phoebe. By default, * `deployPhoebeFixture` already syncs the solo operator during * `autoBootstrap`. Call this again to add / deactivate additional * operators. */ automatonSync(opts: { automaton: Address; isActive: boolean; }): Promise; /** * Build a 256-leaf snapshot tree from the supplied sparse leaves, sign * the root with the fixture's `groupSk` (solo mode), and submit * `PushSnapshot` from the fixture's operator. Returns the tree so * subsequent `requestPrice` calls can build proofs from it. * * @param opts.leaves — sparse map of feedId → PriceLeaf. Empty slots are * filled with the canonical placeholder leaf. * @param opts.timestamp — defaults to current `blockchain.now`. */ pushSnapshot(opts: { leaves: ReadonlyMap; timestamp?: number; }): Promise<{ tree: PhoebeMerkleTree; result: SendMessageResult; root: bigint; }>; /** * Send a `RequestPrice` from a consumer treasury, using the supplied * tree + leaf for proof construction. The Phoebe contract will deliver * the FulfillPrice callback to the consumer (a plain treasury bounces * it back, which is fine for flow testing). * * @param opts.consumer — defaults to `phoebeOwner` (any sender works for the pull path). * @param opts.tree — typically the tree returned from a prior `pushSnapshot`. * @param opts.feedId — slot to pull. * @param opts.leaf — REQUIRED: claimed leaf at `feedId`. Pass the same PriceLeaf * you stored at `feedId` when you called `pushSnapshot`. The * contract will assert leaf.feedId == msg.feedId AND that * the leaf's hash matches what the proof walks to. * @param opts.queryId — consumer-supplied; defaults to a monotone counter. */ requestPrice(opts: { tree: PhoebeMerkleTree; feedId: number; leaf: PriceLeaf; queryId?: bigint; consumer?: SandboxContract; maxStaleness?: number; /** Optional fresh-update path — see `SendRequestPriceOpts.freshUpdate` for semantics. Wraps `{ signedData: 68B, sig: 96B }`. */ freshUpdate?: { signedData: Buffer; sig: Buffer; }; }): Promise; /** * Admit Phoebe as an Atlas verifier. Called automatically when * `autoBootstrap !== false`; useful to call manually if you set * `autoBootstrap: false` and want to exercise the admission receiver. */ admitAtAtlas(): Promise; /** Pull live Phoebe config — e.g. `expect(cfg.pullFee).toBe(…)`. */ getConfig(): Promise; } /** * Deploy a fresh Phoebe + real Atlas + mock-ForgeTON inside an existing * sandbox `Blockchain`. By default returns a fully-bootstrapped oracle — * group key cached, operator mirrored, ready for PushSnapshot immediately. * * @example * import { Blockchain } from '@ton/sandbox'; * import { deployPhoebeFixture } from '@titon-network/phoebe-sdk/testing'; * * const blockchain = await Blockchain.create(); * const { phoebe, pushSnapshot, requestPrice } = await deployPhoebeFixture(blockchain); * * // Push a snapshot containing one non-trivial leaf at slot 42: * const sampleLeaf = { feedId: 42, mantissa: 6_543_210n * 100_000_000n, expo: -8, * confBps: 50, pubTime: 2_000_000_000 }; * const { tree } = await pushSnapshot({ leaves: new Map([[42, sampleLeaf]]) }); * * // Pull it: * await requestPrice({ tree, feedId: 42, queryId: 1n }); */ export declare function deployPhoebeFixture(blockchain: Blockchain, opts?: DeployPhoebeFixtureOpts): Promise;