pangu-sdk 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/dbc/index.ts","../src/dbc/template.ts","../src/constants.ts","../src/idl/pangu.json","../src/inputs.ts","../src/dbc/budget.ts","../src/dbc/state.ts","../src/accounts.ts","../src/addresses.ts","../src/coder.ts","../src/dbc/open.ts","../src/instructions.ts","../src/dbc/trade.ts","../src/dbc/quote.ts","../src/dbc/hook.ts","../src/dbc/preflight.ts","../src/band.ts","../src/errors.ts","../src/feed.ts","../src/dbc/credential.ts","../src/dbc/fees.ts","../src/dbc/graduate.ts"],"sourcesContent":["/**\n * Everything a Pangu sale does on Meteora's Dynamic Bonding Curve: open the\n * launch template, open the sale, trade in it, claim the fees, graduate it.\n *\n * This entry point pulls in `@meteora-ag/dynamic-bonding-curve-sdk`. The core\n * entry point does not, so a page that only reads a sale stays small.\n */\n\nexport { launchTemplateTransaction, panguCurve, FORCED } from \"./template.js\";\nexport type { LaunchTemplateInput, LaunchTemplate } from \"./template.js\";\n\nexport { openSaleTransaction, capFromShare } from \"./open.js\";\nexport type { OpenSaleInput, OpenSale, SaleTerms } from \"./open.js\";\n\nexport { buyTransaction, sellTransaction } from \"./trade.js\";\nexport type { BuyInput, SellInput, TradeTransaction } from \"./trade.js\";\n\nexport { preflightBuy } from \"./preflight.js\";\nexport type { PreflightBuyInput, BuyPreflight } from \"./preflight.js\";\n\nexport { claimFeesTransaction } from \"./fees.js\";\nexport type { ClaimFeesInput, ClaimFees } from \"./fees.js\";\n\nexport { graduateTransaction, saleProgress } from \"./graduate.js\";\nexport type { GraduateInput, Graduate, SaleProgress } from \"./graduate.js\";\n\nexport { hookAccounts, hookAccountsInfo } from \"./hook.js\";\nexport type { HookAccountsInput, PendingTokenAccount } from \"./hook.js\";\n\nexport { loadPool, loadSellPool, requireSale, dbcProgram, DBC_POOL_AUTHORITY } from \"./state.js\";\nexport type { PoolView, PoolMarket, SellView } from \"./state.js\";\n\nexport {\n COMPUTE_LIMIT,\n TRANSACTION_SIZE_LIMIT,\n transactionBytes,\n requireOneTransaction,\n} from \"./budget.js\";\n","import { Keypair, type Connection, type PublicKey, type Transaction } from \"@solana/web3.js\";\nimport {\n CollectFeeMode,\n DynamicBondingCurveClient,\n MigrationOption,\n TokenAuthorityOption,\n TokenType,\n buildCurve,\n hasMintAuthority,\n type BuildCurveParams,\n} from \"@meteora-ag/dynamic-bonding-curve-sdk\";\nimport { PANGU_PROGRAM_ID } from \"../constants.js\";\nimport { PanguInputError, requireRealPublicKey } from \"../inputs.js\";\nimport { requireOneTransaction } from \"./budget.js\";\nimport { readyToSign } from \"./state.js\";\n\n/**\n * The settings a Pangu sale cannot work without.\n *\n * Token-2022 base: a transfer hook only exists on Token-2022.\n * The hook program: Pangu itself, or no rule is ever applied.\n * DAMM v2 migration: where a finished sale graduates to.\n * Fees in the paying token only: C11 in the threat model. With fees collected\n * in the sale token, a fee claim would move the sale token while the hook is\n * live, past every cap and approval.\n * The token authority option: C14. It decides whether DBC leaves the mint\n * authority alive at pool creation, and a token that can still be minted is one\n * the hook can never hold to a cap.\n */\nexport const FORCED = {\n tokenType: TokenType.Token2022,\n tokenUpdateAuthority: TokenAuthorityOption.CreatorUpdateAuthority,\n collectFeeMode: CollectFeeMode.QuoteToken,\n migrationOption: MigrationOption.MET_DAMM_V2,\n transferHookProgram: PANGU_PROGRAM_ID,\n} as const;\n\nfunction forced<T>(\n given: T | undefined,\n wanted: T,\n field: string,\n why: string\n): T {\n if (given !== undefined && given !== wanted) {\n throw new PanguInputError(\n `${field} is fixed at ${String(wanted)} for a Pangu sale and cannot be set to ${String(given)}: ${why}`\n );\n }\n return wanted;\n}\n\n/**\n * The token authority option, refusing any that leaves the mint authority alive.\n *\n * Minting is not a transfer, so no hook ever sees it. A mint authority left\n * alive is a way to hand any wallet any amount, past the cap and past the\n * approved list, and `create_sale` refuses such a mint with\n * MintAuthorityStillSet. DBC decides it here, at the template, and drops the\n * authority at pool creation for every option that does not say \"and mint\n * authority\". The question asked is Meteora's own `hasMintAuthority`, not a list\n * of option names, so an option they add later is judged by what it does. What\n * this does not cover: who holds the update authority, which only changes the\n * token's metadata and is the issuer's to choose.\n */\nfunction withoutMintAuthority(\n given: TokenAuthorityOption | undefined\n): TokenAuthorityOption {\n if (given === undefined) {\n return FORCED.tokenUpdateAuthority;\n }\n if (hasMintAuthority(given)) {\n throw new PanguInputError(\n `curve.token.tokenAuthorityOption ${String(given)} leaves the mint authority alive, and Pangu will not open a sale on a token that can still be minted: use CreatorUpdateAuthority, Immutable or PartnerUpdateAuthority`\n );\n }\n return given;\n}\n\n/**\n * The caller's curve with Pangu's own settings put in.\n *\n * Anything else about the curve, the supply, the graduation threshold, the fee\n * schedule, the liquidity split, is the issuer's to choose. Exported so the app\n * can show what it will send before anybody signs.\n *\n * Throws PanguInputError when the caller set one of Pangu's settings to\n * something else, or asked for a token that can still be minted.\n */\nexport function panguCurve(curve: BuildCurveParams): BuildCurveParams {\n if (curve === null || typeof curve !== \"object\") {\n throw new PanguInputError(\"curve must be the parameters buildCurve takes\");\n }\n return {\n ...curve,\n token: {\n ...curve.token,\n tokenType: forced(\n curve.token?.tokenType,\n FORCED.tokenType,\n \"curve.token.tokenType\",\n \"a transfer hook only exists on Token-2022\"\n ),\n tokenAuthorityOption: withoutMintAuthority(curve.token?.tokenAuthorityOption),\n },\n fee: {\n ...curve.fee,\n collectFeeMode: forced(\n curve.fee?.collectFeeMode,\n FORCED.collectFeeMode,\n \"curve.fee.collectFeeMode\",\n \"fees taken in the sale token would move it past every cap and approval\"\n ),\n },\n migration: {\n ...curve.migration,\n migrationOption: forced(\n curve.migration?.migrationOption,\n FORCED.migrationOption,\n \"curve.migration.migrationOption\",\n \"a Pangu sale graduates to DAMM v2\"\n ),\n },\n };\n}\n\nexport interface LaunchTemplateInput {\n connection: Connection;\n /** The partner opening the template. Pays unless a payer is given. */\n partner: PublicKey;\n payer?: PublicKey;\n /** The token buyers pay in. */\n quoteMint: PublicKey;\n curve: BuildCurveParams;\n /** Who may claim the partner's share of the trading fees. Defaults to partner. */\n feeClaimer?: PublicKey;\n /** Who receives tokens left on the curve at graduation. Defaults to partner. */\n leftoverReceiver?: PublicKey;\n /** DBC's badge for a paying token that needs one, such as a stock token. */\n tokenBadge?: PublicKey;\n /** The hook program. Only Pangu's own id is allowed. */\n transferHookProgram?: PublicKey;\n}\n\nexport interface LaunchTemplate {\n transaction: Transaction;\n /** The new template's account. It signs this transaction once. */\n config: Keypair;\n bytes: number;\n}\n\n/**\n * Builds the launch template every Pangu sale is opened from.\n *\n * Wraps Meteora's `createConfigWithTransferHook` and fixes the settings a Pangu\n * sale depends on, refusing any attempt to set them otherwise. Signs and\n * sends nothing: the partner signs the returned transaction together with the\n * returned config keypair.\n *\n * Throws PanguInputError for a forced setting the caller tried to override, or\n * for a transaction that would not fit.\n */\nexport async function launchTemplateTransaction(\n input: LaunchTemplateInput\n): Promise<LaunchTemplate> {\n const partner = requireRealPublicKey(input.partner, \"partner\");\n const payer = input.payer === undefined ? partner : requireRealPublicKey(input.payer, \"payer\");\n const quoteMint = requireRealPublicKey(input.quoteMint, \"quoteMint\");\n forced(\n input.transferHookProgram?.toBase58(),\n FORCED.transferHookProgram.toBase58(),\n \"transferHookProgram\",\n \"the sale's rules live in Pangu, so Pangu has to be the hook\"\n );\n\n const client = new DynamicBondingCurveClient(input.connection, \"confirmed\");\n const config = Keypair.generate();\n const transaction = await client.partner.createConfigWithTransferHook({\n config: config.publicKey,\n feeClaimer: input.feeClaimer ?? partner,\n leftoverReceiver: input.leftoverReceiver ?? partner,\n payer,\n quoteMint,\n tokenBadge: input.tokenBadge,\n transferHookProgram: FORCED.transferHookProgram,\n ...buildCurve(panguCurve(input.curve)),\n });\n\n await readyToSign(input.connection, transaction, payer);\n return {\n transaction,\n config,\n bytes: requireOneTransaction(transaction, \"the launch template\"),\n };\n}\n","import { PublicKey } from \"@solana/web3.js\";\nimport { TOKEN_2022_PROGRAM_ID } from \"@solana/spl-token\";\nimport type { Idl } from \"@anchor-lang/core\";\nimport idlJson from \"./idl/pangu.json\";\n\n/**\n * The generated interface of the Pangu program, copied from the program's build\n * by `npm run sync-idl`. Everything else in this package is derived from it, so\n * a rebuilt program cannot leave a stale discriminator or error code behind.\n */\nexport const PANGU_IDL = idlJson as Idl;\n\nexport const PANGU_PROGRAM_ID = new PublicKey(PANGU_IDL.address);\n\n/** Meteora's Dynamic Bonding Curve. Source: programs/pangu/src/dbc.rs. */\nexport const DBC_PROGRAM_ID = new PublicKey(\n \"dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN\"\n);\n\n/** The Solana Attestation Service. Source: programs/pangu/src/sas.rs. */\nexport const SAS_PROGRAM_ID = new PublicKey(\n \"22zoJMtdu4tQc2PzL74ZUT7FrwgB1Udec8DdW4yw4BdG\"\n);\n\n/**\n * Pyth's price feed program. Every price feed account is a program address of\n * this program over a shard id and a feed id, so a sale can name the address\n * before anybody has ever refreshed it.\n * Source: programs/pangu/src/price.rs, PRICE_FEED_PROGRAM_ID.\n */\nexport const PYTH_PRICE_FEED_PROGRAM_ID = new PublicKey(\n \"pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT\"\n);\n\n/**\n * Pyth's receiver program, the only program that can write a price feed\n * account, and only after checking the Wormhole guardians' signatures.\n * Source: programs/pangu/src/price.rs, RECEIVER_PROGRAM_ID.\n */\nexport const PYTH_RECEIVER_PROGRAM_ID = new PublicKey(\n \"rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ\"\n);\n\n/**\n * The Pyth shard Pangu refreshes. A shard is a second copy of the same feed at\n * a second address, so a sale depends on a price Pangu's own refresher keeps\n * fresh rather than on the sponsored one.\n * Source: programs/pangu/src/price.rs, PANGU_SHARD_ID.\n */\nexport const PANGU_SHARD_ID = 7_700;\n\nexport { TOKEN_2022_PROGRAM_ID };\n\n/**\n * The SaleRules layouts this package reads. Source: state.rs,\n * SALE_RULES_OLDEST_READABLE_VERSION to SALE_RULES_LAYOUT_VERSION. Version 2\n * added the paying token and the end of the offering period in what used to be\n * spare bytes, so a version 1 account is the same size with every older field\n * in place. An account carrying any other number was written by a different\n * build of the program, so every field behind the version byte may sit\n * somewhere else.\n */\nexport const SALE_RULES_LAYOUT_VERSIONS: ReadonlySet<number> = new Set([1, 2]);\n\nexport const ACCESS_MODE = {\n open: 0,\n issuerList: 1,\n verifierCredential: 2,\n} as const;\n\nexport type AccessMode = (typeof ACCESS_MODE)[keyof typeof ACCESS_MODE];\n\n/**\n * The seed prefixes the program and its neighbours derive addresses from.\n * Source: state.rs (sale, buyer, extra-account-metas), sas.rs (attestation),\n * the attestation service source (credential, schema), dbc.rs (token_vault).\n */\nexport const SEEDS = {\n sale: \"sale\",\n buyer: \"buyer\",\n extraAccountMetas: \"extra-account-metas\",\n attestation: \"attestation\",\n credential: \"credential\",\n schema: \"schema\",\n dbcTokenVault: \"token_vault\",\n} as const;\n\n/**\n * The limits the program itself enforces. Each one names the Rust constant or\n * check it copies, so a change on chain has one place to land here.\n */\nexport const LIMITS = {\n /** price.rs MAX_BAND_BPS: half again over the live stock price. */\n maxBandBps: 5_000,\n minBandBps: 1,\n /** price.rs MAX_PRICE_AGE_SECS, and create_sale.rs check_band takes 1..=3600. */\n maxPriceAgeSecs: 3_600,\n minPriceAgeSecs: 1,\n /** price.rs MAX_CONF_BPS: ten percent, and check_band takes 1..=1000. */\n maxConfBps: 1_000,\n minConfBps: 1,\n /** price.rs MAX_DECIMALS. */\n maxDecimals: 18,\n /** Every Pyth feed id is 32 bytes. */\n feedIdLength: 32,\n /** A Pyth shard id is a u16, which is what the address seed holds. */\n maxShard: 65_535,\n /** u64 raw token units, the widest cap the program can hold. */\n maxCap: (1n << 64n) - 1n,\n} as const;\n\n/**\n * The paying tokens each build of the program accepts under a price ceiling.\n * Source: create_sale.rs, DOLLAR_MINTS, which differs between the mainnet build\n * and the devnet build (feature \"devnet\"). Circle's devnet USDC and the demo\n * dollar mean nothing on mainnet, which is why the lists are separate.\n */\nconst DOLLAR_MINT_ADDRESSES = {\n mainnet: [\"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\"],\n devnet: [\n \"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\",\n \"2TYsrKmXKrqxLRULNBGFrGjTnxebo1H2azRb7bzQPem5\",\n ],\n} as const;\n\n/**\n * The dollar tokens a banded sale can be paid in on `network`, in the order the\n * program lists them. A fresh array each call, so a caller cannot change the\n * list another caller reads.\n *\n * Covers the exact addresses the program checks. Does not say whether a listed\n * stablecoin still holds its peg. Throws for any network other than \"devnet\" or\n * \"mainnet\", because guessing a list would let a ceiling through the program\n * then refuses.\n */\nexport function dollarMints(network: \"devnet\" | \"mainnet\"): PublicKey[] {\n if (!Object.prototype.hasOwnProperty.call(DOLLAR_MINT_ADDRESSES, network)) {\n throw new Error(`no dollar list for network \"${String(network)}\": use \"devnet\" or \"mainnet\"`);\n }\n return DOLLAR_MINT_ADDRESSES[network].map((address) => new PublicKey(address));\n}\n","{\n \"address\": \"4Nd46mDiaTSkqXPAXKqT4jkahcz1TxVSdoirbBCAr5qG\",\n \"metadata\": {\n \"name\": \"pangu\",\n \"version\": \"0.1.0\",\n \"spec\": \"0.1.0\",\n \"description\": \"Rules for a fair first sale of a stock token on Meteora DBC\"\n },\n \"docs\": [\n \"Pangu holds the rules of a stock token's first sale on Meteora's Dynamic Bonding\",\n \"Curve: a cap per wallet, an optional issuer-approved buyer list, an optional\",\n \"ceiling against the real stock's live price, and no wallet-to-wallet movement\",\n \"until the sale is over. DBC finds the price, Pangu decides who may receive\",\n \"tokens and how many.\"\n ],\n \"instructions\": [\n {\n \"name\": \"approve_buyer\",\n \"discriminator\": [\n 193,\n 6,\n 144,\n 245,\n 24,\n 184,\n 227,\n 19\n ],\n \"accounts\": [\n {\n \"name\": \"issuer\",\n \"writable\": true,\n \"signer\": true,\n \"relations\": [\n \"rules\"\n ]\n },\n {\n \"name\": \"mint\",\n \"relations\": [\n \"rules\"\n ]\n },\n {\n \"name\": \"rules\",\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 115,\n 97,\n 108,\n 101\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint\"\n }\n ]\n }\n },\n {\n \"name\": \"record\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 98,\n 117,\n 121,\n 101,\n 114\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint\"\n },\n {\n \"kind\": \"arg\",\n \"path\": \"wallet\"\n }\n ]\n }\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n }\n ],\n \"args\": [\n {\n \"name\": \"wallet\",\n \"type\": \"pubkey\"\n }\n ]\n },\n {\n \"name\": \"close_buyer_record\",\n \"discriminator\": [\n 27,\n 105,\n 238,\n 144,\n 158,\n 212,\n 40,\n 114\n ],\n \"accounts\": [\n {\n \"name\": \"wallet\",\n \"writable\": true,\n \"signer\": true,\n \"relations\": [\n \"record\"\n ]\n },\n {\n \"name\": \"mint\",\n \"relations\": [\n \"record\"\n ]\n },\n {\n \"name\": \"record\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 98,\n 117,\n 121,\n 101,\n 114\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint\"\n },\n {\n \"kind\": \"account\",\n \"path\": \"wallet\"\n }\n ]\n }\n },\n {\n \"name\": \"rules\",\n \"docs\": [\n \"offering period is over, and only when the bytes are a SaleRules in a\",\n \"layout this build reads. Anything else, including rules written by an\",\n \"older build, reads as \\\"not over\\\" and leaves the two older ways in exactly\",\n \"as they were, so this account can never stop a close that worked before.\"\n ],\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 115,\n 97,\n 108,\n 101\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint\"\n }\n ]\n }\n }\n ],\n \"args\": []\n },\n {\n \"name\": \"create_sale\",\n \"discriminator\": [\n 137,\n 197,\n 124,\n 245,\n 254,\n 35,\n 17,\n 12\n ],\n \"accounts\": [\n {\n \"name\": \"issuer\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"pool\",\n \"docs\": [\n \"owning program, the length and the discriminator before any field is used.\"\n ]\n },\n {\n \"name\": \"mint\",\n \"docs\": [\n \"owning program is checked there before the bytes are read.\"\n ]\n },\n {\n \"name\": \"credential\",\n \"docs\": [\n \"key named in `credential`, owned by the attestation service, and to carry\",\n \"the credential discriminator. Refused outright in the other modes.\"\n ],\n \"optional\": true\n },\n {\n \"name\": \"schema\",\n \"docs\": [\n \"key named in `schema`, owned by the attestation service, to belong to\",\n \"`credential`, and not to be paused. Refused outright in the other modes.\"\n ],\n \"optional\": true\n },\n {\n \"name\": \"dbc_config\",\n \"docs\": [\n \"template this pool names, owned by DBC and of the right kind. Its fee mode\",\n \"and the supply its curve sells decide whether the sale may open at all, and\",\n \"it names the paying token.\"\n ]\n },\n {\n \"name\": \"quote_mint\",\n \"docs\": [\n \"Required in every mode. Must be the paying token the template names. It is\",\n \"stored in the rules, its freeze authority is checked, and on a banded sale\",\n \"its decimals are stored so the hook can turn a curve price into dollars\",\n \"without being handed a mint at buy time.\"\n ]\n },\n {\n \"name\": \"rules\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 115,\n 97,\n 108,\n 101\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint\"\n }\n ]\n }\n },\n {\n \"name\": \"extra_account_meta_list\",\n \"docs\": [\n \"seeds the transfer-hook interface requires, and `init` makes it single-use.\"\n ],\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 101,\n 120,\n 116,\n 114,\n 97,\n 45,\n 97,\n 99,\n 99,\n 111,\n 117,\n 110,\n 116,\n 45,\n 109,\n 101,\n 116,\n 97,\n 115\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint\"\n }\n ]\n }\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n }\n ],\n \"args\": [\n {\n \"name\": \"cap\",\n \"type\": \"u64\"\n },\n {\n \"name\": \"access_mode\",\n \"type\": \"u8\"\n },\n {\n \"name\": \"credential\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"schema\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"band\",\n \"type\": {\n \"defined\": {\n \"name\": \"PriceBand\"\n }\n }\n },\n {\n \"name\": \"ends_at\",\n \"type\": \"i64\"\n }\n ]\n },\n {\n \"name\": \"execute\",\n \"discriminator\": [\n 105,\n 37,\n 101,\n 197,\n 75,\n 251,\n 102,\n 26\n ],\n \"accounts\": [\n {\n \"name\": \"source_token\",\n \"docs\": [\n \"owning program is checked. Nothing is read from it before that.\"\n ]\n },\n {\n \"name\": \"mint\",\n \"docs\": [\n \"the rules account is proven to be the one derived from it.\"\n ],\n \"relations\": [\n \"rules\"\n ]\n },\n {\n \"name\": \"destination_token\",\n \"docs\": [\n \"owning program is checked.\"\n ]\n },\n {\n \"name\": \"authority\",\n \"docs\": [\n \"because a signature proves nothing about who is allowed to receive tokens.\"\n ]\n },\n {\n \"name\": \"extra_account_meta_list\",\n \"docs\": [\n \"Token-2022 resolves the extra accounts from it before the call. Pangu itself\",\n \"reads nothing out of it, so it is carried, not trusted.\"\n ]\n },\n {\n \"name\": \"rules\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 115,\n 97,\n 108,\n 101\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint\"\n }\n ]\n }\n },\n {\n \"name\": \"destination_record\",\n \"docs\": [\n \"program, discriminator, mint and wallet are all checked by hand below.\"\n ],\n \"writable\": true\n },\n {\n \"name\": \"source_record\",\n \"docs\": [\n \"program, discriminator, mint and wallet are all checked by hand below.\"\n ],\n \"writable\": true\n }\n ],\n \"args\": [\n {\n \"name\": \"amount\",\n \"type\": \"u64\"\n }\n ]\n },\n {\n \"name\": \"open_buyer_record\",\n \"discriminator\": [\n 216,\n 212,\n 35,\n 190,\n 138,\n 99,\n 66,\n 197\n ],\n \"accounts\": [\n {\n \"name\": \"wallet\",\n \"writable\": true,\n \"signer\": true\n },\n {\n \"name\": \"mint\"\n },\n {\n \"name\": \"rules\",\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 115,\n 97,\n 108,\n 101\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint\"\n }\n ]\n }\n },\n {\n \"name\": \"record\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 98,\n 117,\n 121,\n 101,\n 114\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint\"\n },\n {\n \"kind\": \"account\",\n \"path\": \"wallet\"\n }\n ]\n }\n },\n {\n \"name\": \"system_program\",\n \"address\": \"11111111111111111111111111111111\"\n }\n ],\n \"args\": []\n },\n {\n \"name\": \"revoke_buyer\",\n \"discriminator\": [\n 78,\n 97,\n 108,\n 126,\n 172,\n 157,\n 228,\n 134\n ],\n \"accounts\": [\n {\n \"name\": \"issuer\",\n \"signer\": true,\n \"relations\": [\n \"rules\"\n ]\n },\n {\n \"name\": \"mint\",\n \"relations\": [\n \"rules\",\n \"record\"\n ]\n },\n {\n \"name\": \"rules\",\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 115,\n 97,\n 108,\n 101\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint\"\n }\n ]\n }\n },\n {\n \"name\": \"record\",\n \"writable\": true,\n \"pda\": {\n \"seeds\": [\n {\n \"kind\": \"const\",\n \"value\": [\n 98,\n 117,\n 121,\n 101,\n 114\n ]\n },\n {\n \"kind\": \"account\",\n \"path\": \"mint\"\n },\n {\n \"kind\": \"arg\",\n \"path\": \"wallet\"\n }\n ]\n }\n }\n ],\n \"args\": [\n {\n \"name\": \"wallet\",\n \"type\": \"pubkey\"\n }\n ]\n }\n ],\n \"accounts\": [\n {\n \"name\": \"BuyerRecord\",\n \"discriminator\": [\n 107,\n 122,\n 54,\n 31,\n 4,\n 54,\n 209,\n 38\n ]\n },\n {\n \"name\": \"SaleRules\",\n \"discriminator\": [\n 39,\n 103,\n 95,\n 70,\n 15,\n 23,\n 201,\n 128\n ]\n }\n ],\n \"events\": [\n {\n \"name\": \"Bought\",\n \"discriminator\": [\n 193,\n 56,\n 215,\n 24,\n 156,\n 76,\n 42,\n 104\n ]\n },\n {\n \"name\": \"BuyerApproved\",\n \"discriminator\": [\n 146,\n 41,\n 51,\n 7,\n 192,\n 96,\n 249,\n 196\n ]\n },\n {\n \"name\": \"BuyerRecordClosed\",\n \"discriminator\": [\n 175,\n 245,\n 14,\n 122,\n 129,\n 113,\n 23,\n 155\n ]\n },\n {\n \"name\": \"BuyerRecordOpened\",\n \"discriminator\": [\n 249,\n 239,\n 77,\n 35,\n 176,\n 81,\n 45,\n 85\n ]\n },\n {\n \"name\": \"BuyerRevoked\",\n \"discriminator\": [\n 116,\n 129,\n 248,\n 92,\n 255,\n 222,\n 13,\n 59\n ]\n },\n {\n \"name\": \"SaleCreated\",\n \"discriminator\": [\n 164,\n 187,\n 32,\n 35,\n 143,\n 167,\n 235,\n 132\n ]\n },\n {\n \"name\": \"SoldBack\",\n \"discriminator\": [\n 153,\n 215,\n 200,\n 12,\n 194,\n 138,\n 190,\n 253\n ]\n }\n ],\n \"errors\": [\n {\n \"code\": 6000,\n \"name\": \"NotTransferring\",\n \"msg\": \"Token-2022 is not mid-transfer on both token accounts\"\n },\n {\n \"code\": 6001,\n \"name\": \"ReceivingAccountOwnerCanChange\",\n \"msg\": \"the receiving token account's owner can still be changed\"\n },\n {\n \"code\": 6002,\n \"name\": \"WrongMint\",\n \"msg\": \"the account does not belong to this sale's mint\"\n },\n {\n \"code\": 6003,\n \"name\": \"WrongBuyerRecord\",\n \"msg\": \"the buyer record is not the one for this wallet\"\n },\n {\n \"code\": 6004,\n \"name\": \"BuyerRecordMissing\",\n \"msg\": \"this wallet has no buyer record yet\"\n },\n {\n \"code\": 6005,\n \"name\": \"NotApproved\",\n \"msg\": \"this wallet is not on the issuer's approved list\"\n },\n {\n \"code\": 6006,\n \"name\": \"CredentialInvalid\",\n \"msg\": \"the attestation is not valid for this wallet, credential and schema\"\n },\n {\n \"code\": 6007,\n \"name\": \"CredentialExpired\",\n \"msg\": \"the attestation has expired\"\n },\n {\n \"code\": 6008,\n \"name\": \"CredentialSignerNotAuthorized\",\n \"msg\": \"the key that signed the attestation is no longer an authorized signer\"\n },\n {\n \"code\": 6009,\n \"name\": \"OverCap\",\n \"msg\": \"this buy would take the wallet over the per-wallet cap\"\n },\n {\n \"code\": 6010,\n \"name\": \"WalletToWalletDuringSale\",\n \"msg\": \"the token cannot move between wallets while the sale is running\"\n },\n {\n \"code\": 6011,\n \"name\": \"PriceStale\",\n \"msg\": \"the reference price is too old, missing or not a positive number\"\n },\n {\n \"code\": 6012,\n \"name\": \"PriceOutsideBand\",\n \"msg\": \"the price is outside the allowed band\"\n },\n {\n \"code\": 6013,\n \"name\": \"WrongPriceAccount\",\n \"msg\": \"the price account is not the one named in the rules, or does not hold a usable price\"\n },\n {\n \"code\": 6014,\n \"name\": \"PriceNotFullyVerified\",\n \"msg\": \"the price update has not been signed by two thirds of the guardians\"\n },\n {\n \"code\": 6015,\n \"name\": \"PriceTooUncertain\",\n \"msg\": \"the price carries a wider confidence interval than this sale accepts\"\n },\n {\n \"code\": 6016,\n \"name\": \"NotPoolCreator\",\n \"msg\": \"the signer did not create this pool\"\n },\n {\n \"code\": 6017,\n \"name\": \"NotAHookPool\",\n \"msg\": \"the account is not a DBC transfer-hook pool\"\n },\n {\n \"code\": 6018,\n \"name\": \"HookProgramMismatch\",\n \"msg\": \"the mint's transfer hook does not name this program\"\n },\n {\n \"code\": 6019,\n \"name\": \"MintAuthorityStillSet\",\n \"msg\": \"someone can still mint this token, which would go straight past the cap\"\n },\n {\n \"code\": 6020,\n \"name\": \"WrongLaunchTemplate\",\n \"msg\": \"the launch template is not the one this pool was opened on\"\n },\n {\n \"code\": 6021,\n \"name\": \"FeesNotInQuoteToken\",\n \"msg\": \"the launch template collects fees in the sale token instead of the paying token\"\n },\n {\n \"code\": 6022,\n \"name\": \"ZeroCap\",\n \"msg\": \"the cap must be above zero\"\n },\n {\n \"code\": 6023,\n \"name\": \"InvalidAccessMode\",\n \"msg\": \"that access mode is not available\"\n },\n {\n \"code\": 6024,\n \"name\": \"InvalidBand\",\n \"msg\": \"the price band settings are incomplete, out of range, or set on a sale that has no band\"\n },\n {\n \"code\": 6025,\n \"name\": \"SaleStillRunning\",\n \"msg\": \"the sale is still running, the mint still names this program as its hook\"\n },\n {\n \"code\": 6026,\n \"name\": \"NotIssuer\",\n \"msg\": \"only the issuer can do this\"\n },\n {\n \"code\": 6027,\n \"name\": \"MathOverflow\",\n \"msg\": \"the counter would overflow\"\n },\n {\n \"code\": 6028,\n \"name\": \"WrongLayoutVersion\",\n \"msg\": \"these sale rules were written by another layout of the program\"\n },\n {\n \"code\": 6029,\n \"name\": \"BandNeedsDollarQuote\",\n \"msg\": \"a price band needs buyers to pay in a dollar token on this network's list\"\n },\n {\n \"code\": 6030,\n \"name\": \"IssuerControlsPayingToken\",\n \"msg\": \"the issuer can freeze the paying token, which would let them stop sellers being paid\"\n },\n {\n \"code\": 6031,\n \"name\": \"CapCoversWholeSale\",\n \"msg\": \"the cap is at or above everything the curve sells, so it limits nobody\"\n },\n {\n \"code\": 6032,\n \"name\": \"EndInThePast\",\n \"msg\": \"the offering period would end at a time that has already passed\"\n }\n ],\n \"types\": [\n {\n \"name\": \"Bought\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"wallet\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"amount\",\n \"type\": \"u64\"\n },\n {\n \"name\": \"net_bought\",\n \"type\": \"u64\"\n }\n ]\n }\n },\n {\n \"name\": \"BuyerApproved\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"wallet\",\n \"type\": \"pubkey\"\n }\n ]\n }\n },\n {\n \"name\": \"BuyerRecord\",\n \"docs\": [\n \"One wallet's standing in one sale. Keyed on the wallet that owns the token\",\n \"account, never on the token account, so extra token accounts share one cap.\"\n ],\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"wallet\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"approved\",\n \"type\": \"bool\"\n },\n {\n \"name\": \"net_bought\",\n \"docs\": [\n \"Tokens received from the pool minus tokens sold back to it.\"\n ],\n \"type\": \"u64\"\n },\n {\n \"name\": \"bump\",\n \"type\": \"u8\"\n }\n ]\n }\n },\n {\n \"name\": \"BuyerRecordClosed\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"wallet\",\n \"type\": \"pubkey\"\n }\n ]\n }\n },\n {\n \"name\": \"BuyerRecordOpened\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"wallet\",\n \"type\": \"pubkey\"\n }\n ]\n }\n },\n {\n \"name\": \"BuyerRevoked\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"wallet\",\n \"type\": \"pubkey\"\n }\n ]\n }\n },\n {\n \"name\": \"PriceBand\",\n \"docs\": [\n \"The price band settings, passed to `create_sale` as one value.\",\n \"\",\n \"They travel together because they are only meaningful together: the price\",\n \"account's address is derived from the shard id and the feed id, so changing\",\n \"either one changes which account the hook must read.\"\n ],\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"band_bps\",\n \"docs\": [\n \"How far above the live stock price a buy may leave the curve price, in\",\n \"basis points. Zero switches the whole band off.\"\n ],\n \"type\": \"u16\"\n },\n {\n \"name\": \"price_account\",\n \"docs\": [\n \"The Pyth price feed account. Must be the address the shard id and the feed\",\n \"id below produce under Pyth's price feed program.\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"price_feed_id\",\n \"docs\": [\n \"The Pyth feed carrying the stock price in dollars.\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"price_shard\",\n \"docs\": [\n \"Which of Pyth's shards this sale reads. A shard is just a second copy of\",\n \"the same feed at a second address, so a sale can depend on a price its own\",\n \"refresher keeps fresh rather than on Pyth's sponsored one.\"\n ],\n \"type\": \"u16\"\n },\n {\n \"name\": \"max_price_age_secs\",\n \"docs\": [\n \"How old the published price may be on a buy, in seconds.\"\n ],\n \"type\": \"u32\"\n },\n {\n \"name\": \"max_conf_bps\",\n \"docs\": [\n \"The widest confidence interval this sale will buy against, in basis points\",\n \"of the price itself.\"\n ],\n \"type\": \"u16\"\n }\n ]\n }\n },\n {\n \"name\": \"SaleCreated\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"pool\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"issuer\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"base_vault\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"cap\",\n \"type\": \"u64\"\n },\n {\n \"name\": \"access_mode\",\n \"type\": \"u8\"\n },\n {\n \"name\": \"band_bps\",\n \"type\": \"u16\"\n },\n {\n \"name\": \"quote_mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"ends_at\",\n \"docs\": [\n \"Unix seconds when the offering period ends and every rule lifts. Zero\",\n \"means the rules hold until graduation.\"\n ],\n \"type\": \"i64\"\n }\n ]\n }\n },\n {\n \"name\": \"SaleRules\",\n \"docs\": [\n \"The rules of one sale. Written once at creation and never changed: there is no\",\n \"update instruction, which is what makes the cap a promise instead of a setting.\"\n ],\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"pool\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"base_vault\",\n \"docs\": [\n \"The pool's base token vault, read out of the pool account at creation. The\",\n \"hook tells a buy from a sell by comparing against this one address.\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"issuer\",\n \"docs\": [\n \"The pool creator. The only key that can approve or revoke buyers.\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"cap\",\n \"docs\": [\n \"Most tokens one wallet may hold net of sells, in raw units.\"\n ],\n \"type\": \"u64\"\n },\n {\n \"name\": \"access_mode\",\n \"type\": \"u8\"\n },\n {\n \"name\": \"credential\",\n \"docs\": [\n \"Mode 2 only: the attestation credential whose approvals count. Zero\",\n \"otherwise. Sits at byte 145 of the account, and the hook's extra accounts\",\n \"are derived by reading it there, so it can never move.\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"schema\",\n \"docs\": [\n \"Mode 2 only: the attestation schema that counts. Zero otherwise. Sits at\",\n \"byte 177 of the account, read the same way.\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"price_account\",\n \"docs\": [\n \"Band only: the Pyth price feed account, at byte 209. Zero otherwise.\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"price_feed_id\",\n \"docs\": [\n \"Band only: the Pyth feed the price account must carry, at byte 241.\"\n ],\n \"type\": {\n \"array\": [\n \"u8\",\n 32\n ]\n }\n },\n {\n \"name\": \"price_shard\",\n \"docs\": [\n \"Band only: the Pyth shard the price account was derived under.\"\n ],\n \"type\": \"u16\"\n },\n {\n \"name\": \"band_bps\",\n \"docs\": [\n \"Zero means no band.\"\n ],\n \"type\": \"u16\"\n },\n {\n \"name\": \"max_price_age_secs\",\n \"type\": \"u32\"\n },\n {\n \"name\": \"max_conf_bps\",\n \"type\": \"u16\"\n },\n {\n \"name\": \"base_decimals\",\n \"docs\": [\n \"Read off the two mints at creation, so the curve price can be turned into\",\n \"dollars per whole token without trusting anything passed at buy time.\"\n ],\n \"type\": \"u8\"\n },\n {\n \"name\": \"quote_decimals\",\n \"type\": \"u8\"\n },\n {\n \"name\": \"buyers\",\n \"docs\": [\n \"Wallets whose record is above zero right now.\"\n ],\n \"type\": \"u32\"\n },\n {\n \"name\": \"total_net_bought\",\n \"docs\": [\n \"Sum of every record, so the app can show the largest holder's share.\"\n ],\n \"type\": \"u64\"\n },\n {\n \"name\": \"bump\",\n \"type\": \"u8\"\n },\n {\n \"name\": \"layout_version\",\n \"docs\": [\n \"Which layout wrote this account, at byte 298. It takes the first of what\",\n \"used to be the spare bytes, so the account is the same size and every\",\n \"field in front of it sits exactly where it always did. A sale opened\",\n \"before this byte existed reads as version 0, which is how a reader tells\",\n \"the two apart instead of reading one layout's bytes as the other's.\"\n ],\n \"type\": \"u8\"\n },\n {\n \"name\": \"quote_mint\",\n \"docs\": [\n \"The token buyers pay in, read from the launch template at creation, at\",\n \"byte 299. Layout 2 onwards; a version 1 account holds zeros here.\"\n ],\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"ends_at\",\n \"docs\": [\n \"Unix seconds at which the offering period ends, at byte 331. From then on\",\n \"every rule lifts and the token moves freely, so a curve that never fills\",\n \"cannot hold the token in place for good. Zero means no end: the rules hold\",\n \"until graduation. Fixed at creation like every other rule.\"\n ],\n \"type\": \"i64\"\n },\n {\n \"name\": \"reserved\",\n \"type\": {\n \"array\": [\n \"u8\",\n 23\n ]\n }\n }\n ]\n }\n },\n {\n \"name\": \"SoldBack\",\n \"type\": {\n \"kind\": \"struct\",\n \"fields\": [\n {\n \"name\": \"mint\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"wallet\",\n \"type\": \"pubkey\"\n },\n {\n \"name\": \"amount\",\n \"type\": \"u64\"\n },\n {\n \"name\": \"net_bought\",\n \"type\": \"u64\"\n }\n ]\n }\n }\n ]\n}\n","import { PublicKey } from \"@solana/web3.js\";\n\n/**\n * Thrown before anything is built when an input could never pass on chain.\n *\n * Every message names the rule and the value, because the caller is usually a\n * form in the app and the text goes straight to the person filling it in.\n */\nexport class PanguInputError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PanguInputError\";\n }\n}\n\nexport function requirePublicKey(value: unknown, field: string): PublicKey {\n if (!(value instanceof PublicKey)) {\n throw new PanguInputError(`${field} must be a PublicKey`);\n }\n return value;\n}\n\n/** A key that is present and is not the all zero address the program reads as \"unset\". */\nexport function requireRealPublicKey(value: unknown, field: string): PublicKey {\n const key = requirePublicKey(value, field);\n if (key.equals(PublicKey.default)) {\n throw new PanguInputError(`${field} must not be the all zero address`);\n }\n return key;\n}\n\nexport function requireAbsent(value: unknown, field: string, reason: string): void {\n if (value !== undefined && value !== null) {\n throw new PanguInputError(`${field} ${reason}`);\n }\n}\n\n/** An unsigned whole number inside the range the program's own field can hold. */\nexport function requireWholeNumber(\n value: unknown,\n field: string,\n low: number,\n high: number\n): number {\n if (typeof value !== \"number\" || !Number.isInteger(value)) {\n throw new PanguInputError(`${field} must be a whole number`);\n }\n if (value < low || value > high) {\n throw new PanguInputError(`${field} must be between ${low} and ${high}, got ${value}`);\n }\n return value;\n}\n\nexport function requireBigint(value: unknown, field: string): bigint {\n if (typeof value === \"bigint\") {\n return value;\n }\n if (typeof value === \"number\" && Number.isInteger(value)) {\n return BigInt(value);\n }\n throw new PanguInputError(`${field} must be a bigint`);\n}\n","import { ComputeBudgetProgram, type Transaction, type TransactionInstruction } from \"@solana/web3.js\";\nimport { PanguInputError } from \"../inputs.js\";\n\n/** One Solana transaction, signatures included. */\nexport const TRANSACTION_SIZE_LIMIT = 1232;\n\n/**\n * The compute limits this package asks for, each set from what the same action\n * really used on a fork of mainnet. The measurements are in\n * docs/measurements/fork-test.md. Roughly double the measured cost, because a\n * banded or credential sale reads more accounts than the plain one that was\n * measured, and running out of compute would look to a buyer like a refusal.\n */\nexport const COMPUTE_LIMIT = {\n /** Measured: 113,000 to 130,000 units for a buy, 83,000 for a sell. */\n swap: 300_000,\n /** Measured: 55,192 for the partner claim, 51,742 for the creator claim. */\n claim: 150_000,\n} as const;\n\nexport function computeLimit(units: number): TransactionInstruction {\n return ComputeBudgetProgram.setComputeUnitLimit({ units });\n}\n\n/**\n * How many bytes this transaction will take on the wire.\n *\n * `serialize()` throws once a transaction passes the limit, and the point of\n * measuring is to find out whether it does, so the size is worked out from the\n * compiled message instead. The fee payer and a blockhash must already be set.\n */\nexport function transactionBytes(transaction: Transaction): number {\n const message = transaction.compileMessage();\n return (\n message.serialize().length + 1 + 64 * message.header.numRequiredSignatures\n );\n}\n\n/** Refuses a transaction that could never be sent, with the action named. */\nexport function requireOneTransaction(\n transaction: Transaction,\n action: string\n): number {\n const bytes = transactionBytes(transaction);\n if (bytes > TRANSACTION_SIZE_LIMIT) {\n throw new PanguInputError(\n `${action} does not fit in one transaction: ${bytes} bytes against the ${TRANSACTION_SIZE_LIMIT} byte limit`\n );\n }\n return bytes;\n}\n","import type { Connection, PublicKey, Transaction } from \"@solana/web3.js\";\nimport {\n BaseFeeMode,\n DynamicBondingCurveClient,\n createDbcProgram,\n deriveDbcPoolAuthority,\n getCurrentPoint,\n getTokenProgram,\n type PoolConfig,\n type VirtualPool,\n} from \"@meteora-ag/dynamic-bonding-curve-sdk\";\nimport type { BN } from \"@anchor-lang/core\";\nimport { getSale, type Sale } from \"../accounts.js\";\nimport { PanguInputError, requirePublicKey } from \"../inputs.js\";\n\n/** DBC's pool authority. Every pool vault is owned by it. */\nexport const DBC_POOL_AUTHORITY = deriveDbcPoolAuthority();\n\n/**\n * Where DBC keeps a pool's base mint. The same offset Meteora's own\n * `getPoolByBaseMint` filters on. Source: ARCHITECTURE.md, \"Offsets inside the\n * pool account\", and programs/pangu/src/dbc.rs, BASE_MINT_OFFSET.\n */\nconst POOL_BASE_MINT_OFFSET = 136;\n\n/** The pool and its launch template: what a trade needs, whatever the rules say. */\nexport interface PoolMarket {\n pool: PublicKey;\n /** The account as DBC's own quote functions want it, with `.poolState` inside. */\n poolAccount: VirtualPool;\n config: PublicKey;\n configState: PoolConfig;\n baseMint: PublicKey;\n quoteMint: PublicKey;\n baseVault: PublicKey;\n quoteVault: PublicKey;\n /** The token program the paying token belongs to, SPL or Token-2022. */\n quoteProgram: PublicKey;\n /** The unit DBC counts the fee schedule in, a slot or a Unix second. */\n currentPoint: BN;\n}\n\n/** Everything a Pangu action needs to know about one live DBC pool. */\nexport interface PoolView extends PoolMarket {\n sale: Sale;\n}\n\n/**\n * What a sell needs. The rules are there when this package can read them and\n * null when it cannot, because a sell never depends on them.\n */\nexport interface SellView extends PoolMarket {\n sale: Sale | null;\n}\n\nexport function dbcProgram(connection: Connection) {\n return createDbcProgram(connection, \"confirmed\").program;\n}\n\n/** The sale's rules, refusing a mint that never had a Pangu sale. */\nexport async function requireSale(\n connection: Connection,\n mint: PublicKey\n): Promise<Sale> {\n const sale = await getSale(connection, requirePublicKey(mint, \"mint\"));\n if (sale === null) {\n throw new PanguInputError(\n `${mint.toBase58()} has no Pangu sale, so there is nothing to trade here`\n );\n }\n return sale;\n}\n\n/**\n * A launch template, whichever of the two shapes DBC stored it in.\n *\n * A transfer hook template is a `configWithTransferHook` account with the\n * ordinary config inside it, not a `poolConfig`, so reading it as a `poolConfig`\n * fails on the discriminator. Meteora's own state service knows both, so it does\n * the reading.\n *\n * Throws PanguInputError when the address is not a launch template at all.\n */\nexport async function loadConfig(\n connection: Connection,\n config: PublicKey\n): Promise<PoolConfig> {\n const client = new DynamicBondingCurveClient(connection, \"confirmed\");\n const state = await client.state.getPoolConfig(config);\n if (state === null) {\n throw new PanguInputError(\n `${config.toBase58()} is not a Meteora launch template`\n );\n }\n return state;\n}\n\n/**\n * Reads the pool and its launch template in one go, for a buy or anything else\n * that acts on the sale's rules.\n *\n * Everything downstream comes from these two accounts rather than from the\n * caller, so a wrong vault or a wrong paying token cannot be passed in.\n *\n * Refuses a mint whose rules this package cannot read, because a buy is judged\n * against them. Refuses a pool whose fee schedule needs the instructions sysvar\n * as its first remaining account: a rate limiter, or the first-swap minimum fee.\n * Pangu's hook accounts are the remaining accounts of every swap, and there is\n * no room for a second thing in that list.\n */\nexport async function loadPool(\n connection: Connection,\n mint: PublicKey\n): Promise<PoolView> {\n const sale = await requireSale(connection, mint);\n return { sale, ...(await readMarket(connection, sale.pool)) };\n}\n\n/**\n * Reads the pool and its launch template for a sell, which never needs the\n * sale's rules.\n *\n * On chain a sell goes through whatever the rules account holds, including rules\n * written by an older build or rules that are missing (C5). This is the same\n * promise on the client side: the rules are read when they can be, and when\n * they cannot, the pool is found by the mint it sells, straight from DBC, and\n * the sell is built anyway. The hook's own accounts are still resolved from the\n * list the program published, so nothing about the hook is guessed.\n *\n * Throws PanguInputError when no transfer hook pool sells this mint, when more\n * than one does, or for the same template refusal as `loadPool`.\n */\nexport async function loadSellPool(\n connection: Connection,\n mint: PublicKey\n): Promise<SellView> {\n const mintKey = requirePublicKey(mint, \"mint\");\n let sale: Sale | null = null;\n try {\n sale = await getSale(connection, mintKey);\n } catch (error) {\n // Only \"these bytes are not rules this package reads\" is swallowed. A\n // network failure is still a failure.\n if (!(error instanceof PanguInputError)) {\n throw error;\n }\n }\n const pool = sale?.pool ?? (await hookPoolSelling(connection, mintKey));\n const market = await readMarket(connection, pool);\n if (!market.baseMint.equals(mintKey)) {\n throw new PanguInputError(\n `${pool.toBase58()} sells ${market.baseMint.toBase58()}, not ${mintKey.toBase58()}`\n );\n }\n return { sale, ...market };\n}\n\n/**\n * The one DBC transfer hook pool whose base mint is this mint, asked of DBC\n * itself. Anchor adds the account discriminator to the filter, so only\n * transfer hook pools come back.\n */\nasync function hookPoolSelling(\n connection: Connection,\n mint: PublicKey\n): Promise<PublicKey> {\n const found = await dbcProgram(connection).account.transferHookPool.all([\n { memcmp: { offset: POOL_BASE_MINT_OFFSET, bytes: mint.toBase58() } },\n ]);\n if (found.length === 0) {\n throw new PanguInputError(\n `no Meteora transfer hook pool sells ${mint.toBase58()}, so there is nothing to sell into`\n );\n }\n if (found.length > 1) {\n throw new PanguInputError(\n `${found.length} transfer hook pools sell ${mint.toBase58()}, and a sell will not pick one on a guess`\n );\n }\n return found[0]!.publicKey;\n}\n\nasync function readMarket(\n connection: Connection,\n pool: PublicKey\n): Promise<PoolMarket> {\n const program = dbcProgram(connection);\n const poolAccount = (await program.account.transferHookPool.fetchNullable(\n pool,\n \"confirmed\"\n )) as VirtualPool | null;\n if (poolAccount === null) {\n throw new PanguInputError(\n `${pool.toBase58()} is not a Meteora transfer hook pool`\n );\n }\n\n const configState = await loadConfig(connection, poolAccount.poolState.config);\n\n if (\n configState.enableFirstSwapWithMinFee ||\n configState.poolFees.baseFee.baseFeeMode === BaseFeeMode.RateLimiter\n ) {\n throw new PanguInputError(\n \"this launch template puts the instructions sysvar in the swap's remaining accounts, where Pangu's hook accounts have to be. Open the sale with launchTemplateTransaction.\"\n );\n }\n\n return {\n pool,\n poolAccount,\n config: poolAccount.poolState.config,\n configState,\n baseMint: poolAccount.poolState.baseMint,\n quoteMint: configState.quoteMint,\n baseVault: poolAccount.poolState.baseVault,\n quoteVault: poolAccount.poolState.quoteVault,\n quoteProgram: getTokenProgram(configState.quoteTokenFlag),\n currentPoint: await getCurrentPoint(connection, configState.activationType),\n };\n}\n\n/** Sets the payer and a fresh blockhash, so the caller can measure and sign. */\nexport async function readyToSign(\n connection: Connection,\n transaction: Transaction,\n payer: PublicKey\n): Promise<Transaction> {\n transaction.feePayer = payer;\n transaction.recentBlockhash = (\n await connection.getLatestBlockhash(\"confirmed\")\n ).blockhash;\n return transaction;\n}\n","import { Buffer } from \"buffer\";\nimport type { BN } from \"@anchor-lang/core\";\nimport type { AccountInfo, Connection, PublicKey } from \"@solana/web3.js\";\nimport { getTransferHook, unpackMint } from \"@solana/spl-token\";\nimport { buyerRecordAddress, feedIdHex, saleRulesAddress } from \"./addresses.js\";\nimport {\n PANGU_PROGRAM_ID,\n SALE_RULES_LAYOUT_VERSIONS,\n TOKEN_2022_PROGRAM_ID,\n} from \"./constants.js\";\nimport { panguCoder } from \"./coder.js\";\nimport { PanguInputError, requirePublicKey } from \"./inputs.js\";\n\nconst SALE_RULES = \"SaleRules\";\nconst BUYER_RECORD = \"BuyerRecord\";\n\n/**\n * Thrown when a SaleRules account was not written by the layout this package\n * reads: the wrong length, or a layout version it does not know.\n *\n * Both are the same failure seen from two sides. Anchor's decoder reads every\n * field at a fixed offset and does not care what wrote the bytes, so an account\n * from another build comes back as a sale with a nonsense cap or a nonsense\n * band rather than as an error. It is a PanguInputError, so a caller that\n * already handles those keeps working.\n */\nexport class PanguLayoutError extends PanguInputError {\n constructor(message: string) {\n super(message);\n this.name = \"PanguLayoutError\";\n }\n}\n\n/** One sale's rules, as the chain holds them. Written once, never updated. */\nexport interface Sale {\n mint: PublicKey;\n pool: PublicKey;\n baseVault: PublicKey;\n issuer: PublicKey;\n /** Raw token units, so a six decimal token's cap of 100 reads as 100000000n. */\n cap: bigint;\n accessMode: number;\n credential: PublicKey;\n schema: PublicKey;\n /** Band only: the Pyth price feed account the hook reads. */\n priceAccount: PublicKey;\n bandBps: number;\n /** Lowercase hex, no prefix, the way the feed scripts print an id. */\n priceFeedId: string;\n /** The Pyth shard the price account was derived under. */\n priceShard: number;\n /** How old the published price may be on a buy, in seconds. */\n maxPriceAgeSecs: number;\n /** The widest confidence interval this sale buys against, in basis points. */\n maxConfBps: number;\n /**\n * Decimals of the sale token. The program only stores these on a sale with a\n * price band, so the chain holds zero for every other sale. `getSale` fills\n * that in from the mint itself; `decodeSale`, which only has the bytes in\n * front of it, hands back the zero the account really holds.\n */\n baseDecimals: number;\n /** Decimals of the paying token, stored only on a sale with a price band. */\n quoteDecimals: number;\n buyers: number;\n totalNetBought: bigint;\n bump: number;\n /** Which layout wrote this account: 1 or 2. */\n layoutVersion: number;\n /**\n * The token buyers pay in, stored by layout 2 onwards. Null on a version 1\n * sale, which never recorded it; its launch template still names it.\n */\n quoteMint: PublicKey | null;\n /**\n * Unix seconds at which the offering period ends and every rule lifts. Null\n * when the sale has no end, which includes every version 1 sale.\n */\n endsAt: number | null;\n /** Spare bytes the program keeps so the account can grow later. */\n reserved: Uint8Array;\n /** True when this sale has a price band, matching SaleRules::has_band. */\n hasBand: boolean;\n}\n\n/** One wallet's standing in one sale. */\nexport interface BuyerRecord {\n mint: PublicKey;\n wallet: PublicKey;\n approved: boolean;\n /** Tokens received from the pool minus tokens sold back, in raw units. */\n netBought: bigint;\n bump: number;\n}\n\ninterface RawSale {\n mint: PublicKey;\n pool: PublicKey;\n base_vault: PublicKey;\n issuer: PublicKey;\n cap: BN;\n access_mode: number;\n credential: PublicKey;\n schema: PublicKey;\n price_account: PublicKey;\n price_feed_id: number[];\n price_shard: number;\n band_bps: number;\n max_price_age_secs: number;\n max_conf_bps: number;\n base_decimals: number;\n quote_decimals: number;\n buyers: number;\n total_net_bought: BN;\n bump: number;\n layout_version: number;\n quote_mint: PublicKey;\n ends_at: BN;\n reserved: number[];\n}\n\ninterface RawBuyerRecord {\n mint: PublicKey;\n wallet: PublicKey;\n approved: boolean;\n net_bought: BN;\n bump: number;\n}\n\nfunction asBuffer(data: Uint8Array): Buffer {\n return Buffer.isBuffer(data) ? data : Buffer.from(data);\n}\n\nfunction big(value: BN): bigint {\n return BigInt(value.toString());\n}\n\nfunction decodeAccount<T>(name: string, data: Uint8Array): T {\n try {\n return panguCoder().accounts.decode<T>(name, asBuffer(data));\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new PanguInputError(`these bytes are not a Pangu ${name}: ${reason}`);\n }\n}\n\n/**\n * Reads a SaleRules account's bytes.\n *\n * The discriminator says these are a SaleRules, then the length and the layout\n * version say which build wrote them. Versions 1 and 2 are read; on version 1\n * the paying token and the end of the offering come back as null, because\n * those bytes were spare zeros then. Anything else throws a `PanguLayoutError`,\n * because an account from another build sits at the same address behind the\n * same discriminator: Anchor reads it without complaint and hands back fields\n * taken from the wrong offsets.\n *\n * Throws `PanguInputError` when the bytes are not a SaleRules at all.\n */\nexport function decodeSale(data: Uint8Array): Sale {\n const raw = decodeAccount<RawSale>(SALE_RULES, data);\n const size = panguCoder().accounts.size(SALE_RULES);\n if (data.length !== size) {\n throw new PanguLayoutError(\n `a SaleRules account is ${size} bytes and these are ${data.length}, so they were written by another build of the program`\n );\n }\n if (!SALE_RULES_LAYOUT_VERSIONS.has(raw.layout_version)) {\n throw new PanguLayoutError(\n `these are layout version ${raw.layout_version} and this package reads versions ${[...SALE_RULES_LAYOUT_VERSIONS].join(\" and \")}, so they were written by another build of the program`\n );\n }\n const newFields = raw.layout_version >= 2;\n const endsAt = newFields ? Number(big(raw.ends_at)) : 0;\n return {\n mint: raw.mint,\n pool: raw.pool,\n baseVault: raw.base_vault,\n issuer: raw.issuer,\n cap: big(raw.cap),\n accessMode: raw.access_mode,\n credential: raw.credential,\n schema: raw.schema,\n priceAccount: raw.price_account,\n bandBps: raw.band_bps,\n priceFeedId: feedIdHex(raw.price_feed_id),\n priceShard: raw.price_shard,\n maxPriceAgeSecs: raw.max_price_age_secs,\n maxConfBps: raw.max_conf_bps,\n baseDecimals: raw.base_decimals,\n quoteDecimals: raw.quote_decimals,\n buyers: raw.buyers,\n totalNetBought: big(raw.total_net_bought),\n bump: raw.bump,\n layoutVersion: raw.layout_version,\n quoteMint: newFields ? raw.quote_mint : null,\n endsAt: endsAt === 0 ? null : endsAt,\n reserved: Uint8Array.from(raw.reserved),\n hasBand: raw.band_bps > 0,\n };\n}\n\n/** Reads a BuyerRecord account's bytes. Throws when they are not a BuyerRecord. */\nexport function decodeBuyerRecord(data: Uint8Array): BuyerRecord {\n const raw = decodeAccount<RawBuyerRecord>(BUYER_RECORD, data);\n return {\n mint: raw.mint,\n wallet: raw.wallet,\n approved: raw.approved,\n netBought: big(raw.net_bought),\n bump: raw.bump,\n };\n}\n\nfunction ownedByPangu(owner: PublicKey, address: PublicKey): void {\n if (!owner.equals(PANGU_PROGRAM_ID)) {\n throw new PanguInputError(\n `${address.toBase58()} is owned by ${owner.toBase58()}, not by Pangu`\n );\n }\n}\n\n/**\n * The rules of the sale for this mint, or null when no sale was ever opened.\n *\n * An account sitting at the rules address that Pangu does not own is refused\n * rather than decoded, because at that point the reader cannot tell what the\n * bytes mean.\n *\n * A sale with no price band stores no decimals, because the hook never needs\n * them, so one more read fills `baseDecimals` from the mint. That keeps every\n * caller turning raw units into an amount a person reads off one field instead\n * of each one remembering the exception. A mint that cannot be read leaves the\n * zero in place.\n */\nexport async function getSale(\n connection: Connection,\n mint: PublicKey\n): Promise<Sale | null> {\n const address = saleRulesAddress(mint);\n const info = await connection.getAccountInfo(address);\n if (info === null) {\n return null;\n }\n ownedByPangu(info.owner, address);\n const sale = decodeSale(info.data);\n if (sale.baseDecimals === 0) {\n const decimals = await mintDecimals(connection, sale.mint);\n if (decimals !== null) {\n return { ...sale, baseDecimals: decimals };\n }\n }\n return sale;\n}\n\nasync function mintDecimals(\n connection: Connection,\n mint: PublicKey\n): Promise<number | null> {\n const info = await connection.getAccountInfo(mint);\n if (info === null || !info.owner.equals(TOKEN_2022_PROGRAM_ID)) {\n return null;\n }\n try {\n return unpackMint(mint, info, TOKEN_2022_PROGRAM_ID).decimals;\n } catch {\n return null;\n }\n}\n\n/** One wallet's record in this sale, or null when the wallet has none yet. */\nexport async function getBuyerRecord(\n connection: Connection,\n mint: PublicKey,\n wallet: PublicKey\n): Promise<BuyerRecord | null> {\n const address = buyerRecordAddress(mint, wallet);\n const info = await connection.getAccountInfo(address);\n if (info === null) {\n return null;\n }\n ownedByPangu(info.owner, address);\n return decodeBuyerRecord(info.data);\n}\n\n/**\n * Every buyer record of one sale.\n *\n * The filter is the record discriminator followed by the sale's mint, which is\n * the record's first field, so the node only returns this sale's records. The\n * caller pays for one scan, and an RPC that refuses getProgramAccounts will\n * throw rather than return a short list.\n */\nexport async function listBuyerRecords(\n connection: Connection,\n mint: PublicKey\n): Promise<BuyerRecord[]> {\n const coder = panguCoder().accounts;\n const accounts = await connection.getProgramAccounts(PANGU_PROGRAM_ID, {\n filters: [\n { dataSize: coder.size(BUYER_RECORD) },\n { memcmp: coder.memcmp(BUYER_RECORD, requirePublicKey(mint, \"mint\").toBuffer()) },\n ],\n });\n return accounts.map((entry) => decodeBuyerRecord(entry.account.data));\n}\n\n/** What `listSales` can be told, beyond the connection. */\nexport interface ListSalesOptions {\n /**\n * Called once for every rules account left out of the list, with its address\n * and the reason in words. Count the calls to know how many were skipped.\n */\n onSkipped?: (address: PublicKey, reason: string) => void;\n}\n\n/**\n * Every sale the Pangu program holds rules for, in no particular order.\n *\n * One scan, filtered by the node on the SaleRules discriminator and on the size\n * this build writes, so buyer records and the larger accounts an earlier build\n * left behind never come back. An account of the right size that this package\n * cannot read, a layout version it does not know, or one that does not sit at\n * the rules address of the mint it names, is skipped and reported through\n * `onSkipped` rather than thrown, so one stray account cannot hide every other\n * sale. Each sale comes back exactly as `decodeSale` reads it, so a sale with no\n * price band still shows zero decimals here; `getSale` or `saleDirectory` fill\n * them from the mint.\n *\n * Throws when the node refuses the scan, because a short list would look like\n * a complete one.\n */\nexport async function listSales(\n connection: Connection,\n options: ListSalesOptions = {}\n): Promise<Sale[]> {\n const coder = panguCoder().accounts;\n const accounts = await connection.getProgramAccounts(PANGU_PROGRAM_ID, {\n filters: [{ dataSize: coder.size(SALE_RULES) }, { memcmp: coder.memcmp(SALE_RULES) }],\n });\n const sales: Sale[] = [];\n for (const entry of accounts) {\n let sale: Sale;\n try {\n sale = decodeSale(entry.account.data);\n } catch (error) {\n if (!(error instanceof PanguInputError)) {\n throw error;\n }\n options.onSkipped?.(entry.pubkey, error.message);\n continue;\n }\n if (!saleRulesAddress(sale.mint).equals(entry.pubkey)) {\n options.onSkipped?.(\n entry.pubkey,\n `these rules name ${sale.mint.toBase58()}, whose rules live at another address`\n );\n continue;\n }\n sales.push(sale);\n }\n return sales;\n}\n\n/**\n * Whether the sale is still running, read off the token itself.\n *\n * The rules live on while the mint names Pangu as its transfer hook. DBC clears\n * that name in the trade that completes the curve, and from then on the token\n * moves freely and any buyer can close their record. This is not a gate on\n * closing: a record holding nothing closes while the sale is still running. A\n * mint that does not exist, is not a Token-2022 mint, or names another hook is\n * not a running Pangu sale.\n */\nexport async function isSaleRunning(\n connection: Connection,\n mint: PublicKey\n): Promise<boolean> {\n const info = await connection.getAccountInfo(requirePublicKey(mint, \"mint\"));\n return mintRunsPangu(mint, info);\n}\n\n/**\n * The running check of `isSaleRunning` on mint bytes already in hand, so a\n * caller that fetched many mints in one call judges each the same way. Throws\n * when a Token-2022 account's bytes are not a mint.\n */\nexport function mintRunsPangu(\n mint: PublicKey,\n info: AccountInfo<Uint8Array> | null\n): boolean {\n if (info === null || !info.owner.equals(TOKEN_2022_PROGRAM_ID)) {\n return false;\n }\n const state = unpackMint(mint, info as AccountInfo<Buffer>, TOKEN_2022_PROGRAM_ID);\n const hook = getTransferHook(state);\n if (hook === null) {\n return false;\n }\n return hook.programId.equals(PANGU_PROGRAM_ID);\n}\n","import { PublicKey } from \"@solana/web3.js\";\nimport {\n DBC_PROGRAM_ID,\n LIMITS,\n PANGU_PROGRAM_ID,\n PANGU_SHARD_ID,\n PYTH_PRICE_FEED_PROGRAM_ID,\n SAS_PROGRAM_ID,\n SEEDS,\n} from \"./constants.js\";\nimport {\n PanguInputError,\n requirePublicKey,\n requireWholeNumber,\n} from \"./inputs.js\";\n\n/** A Pyth feed id, either 32 raw bytes or the same bytes written as hex. */\nexport type FeedId = string | Uint8Array | number[];\n\nconst HEX = /^[0-9a-fA-F]+$/;\n\nfunction seed(text: string): Uint8Array {\n return new TextEncoder().encode(text);\n}\n\n/**\n * The one place a feed id is turned into bytes.\n *\n * Everything that derives an address or encodes an instruction goes through\n * this, so a hex string and a byte array can never be compared after two\n * different readings. A leading \"0x\" is accepted because that is how the feed\n * scripts print ids. Anything that is not exactly 32 bytes is refused.\n */\nexport function feedIdBytes(id: FeedId): Uint8Array {\n let bytes: Uint8Array;\n if (typeof id === \"string\") {\n const text = id.startsWith(\"0x\") || id.startsWith(\"0X\") ? id.slice(2) : id;\n if (text.length !== LIMITS.feedIdLength * 2 || !HEX.test(text)) {\n throw new PanguInputError(\n `a feed id must be ${LIMITS.feedIdLength * 2} hex characters, got \"${id}\"`\n );\n }\n bytes = new Uint8Array(LIMITS.feedIdLength);\n for (let i = 0; i < LIMITS.feedIdLength; i += 1) {\n bytes[i] = Number.parseInt(text.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n }\n if (Array.isArray(id)) {\n if (id.some((byte) => !Number.isInteger(byte) || byte < 0 || byte > 255)) {\n throw new PanguInputError(\"a feed id array must hold whole bytes\");\n }\n bytes = Uint8Array.from(id);\n } else if (id instanceof Uint8Array) {\n bytes = id;\n } else {\n throw new PanguInputError(\"a feed id must be hex or 32 bytes\");\n }\n if (bytes.length !== LIMITS.feedIdLength) {\n throw new PanguInputError(\n `a feed id must be ${LIMITS.feedIdLength} bytes, got ${bytes.length}`\n );\n }\n return bytes;\n}\n\n/** The same id as lowercase hex with no prefix, which is how the feed scripts print it. */\nexport function feedIdHex(id: FeedId): string {\n return Array.from(feedIdBytes(id))\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/** The rules account of one sale. Seeds \"sale\" and the mint. */\nexport function saleRulesAddress(mint: PublicKey): PublicKey {\n return PublicKey.findProgramAddressSync(\n [seed(SEEDS.sale), requirePublicKey(mint, \"mint\").toBuffer()],\n PANGU_PROGRAM_ID\n )[0];\n}\n\n/** One wallet's record in one sale. Seeds \"buyer\", the mint and the wallet. */\nexport function buyerRecordAddress(mint: PublicKey, wallet: PublicKey): PublicKey {\n return PublicKey.findProgramAddressSync(\n [\n seed(SEEDS.buyer),\n requirePublicKey(mint, \"mint\").toBuffer(),\n requirePublicKey(wallet, \"wallet\").toBuffer(),\n ],\n PANGU_PROGRAM_ID\n )[0];\n}\n\n/** The transfer hook's published account list. Seeds fixed by the SPL interface. */\nexport function extraAccountListAddress(mint: PublicKey): PublicKey {\n return PublicKey.findProgramAddressSync(\n [seed(SEEDS.extraAccountMetas), requirePublicKey(mint, \"mint\").toBuffer()],\n PANGU_PROGRAM_ID\n )[0];\n}\n\n/**\n * The one address an attestation for this credential, schema and wallet can have.\n * Derived under the attestation service, not under Pangu.\n */\nexport function attestationAddress(\n credential: PublicKey,\n schema: PublicKey,\n wallet: PublicKey\n): PublicKey {\n return PublicKey.findProgramAddressSync(\n [\n seed(SEEDS.attestation),\n requirePublicKey(credential, \"credential\").toBuffer(),\n requirePublicKey(schema, \"schema\").toBuffer(),\n requirePublicKey(wallet, \"wallet\").toBuffer(),\n ],\n SAS_PROGRAM_ID\n )[0];\n}\n\n/** The pool's base token vault. Derived under DBC, which is what owns it. */\nexport function dbcBaseVaultAddress(mint: PublicKey, pool: PublicKey): PublicKey {\n return PublicKey.findProgramAddressSync(\n [\n seed(SEEDS.dbcTokenVault),\n requirePublicKey(mint, \"mint\").toBuffer(),\n requirePublicKey(pool, \"pool\").toBuffer(),\n ],\n DBC_PROGRAM_ID\n )[0];\n}\n\n/**\n * The one price feed account a Pyth shard and feed id can produce.\n *\n * The seeds are the shard id as two little endian bytes and then the 32 byte\n * feed id, under Pyth's price feed program. The payer is not a seed, so the\n * address is fixed before anybody has refreshed it and nobody can create a\n * rival account for the same shard and feed. This is the same derivation\n * `price_feed_address` runs in programs/pangu/src/price.rs, and the same one\n * `getPriceFeedAccountForProgram` runs in `@pythnetwork/pyth-solana-receiver`.\n *\n * The shard defaults to Pangu's own, which is the shard Pangu's refresher\n * writes. Throws PanguInputError for a shard outside the two bytes it is\n * written into, or a feed id that is not 32 bytes.\n */\nexport function priceFeedAddress(\n feedId: FeedId,\n shard: number = PANGU_SHARD_ID\n): PublicKey {\n const id = feedIdBytes(feedId);\n const shardId = requireWholeNumber(shard, \"shard\", 0, LIMITS.maxShard);\n const seedBytes = new Uint8Array(2);\n seedBytes[0] = shardId & 0xff;\n seedBytes[1] = (shardId >> 8) & 0xff;\n return PublicKey.findProgramAddressSync(\n [seedBytes, id],\n PYTH_PRICE_FEED_PROGRAM_ID\n )[0];\n}\n","import { BorshCoder } from \"@anchor-lang/core\";\nimport { PANGU_IDL } from \"./constants.js\";\n\nlet cached: BorshCoder | null = null;\n\n/**\n * The borsh coder built from the committed IDL.\n *\n * Built on first use rather than at import, so loading this package on a server\n * costs nothing until something is actually encoded or decoded.\n */\nexport function panguCoder(): BorshCoder {\n if (cached === null) {\n cached = new BorshCoder(PANGU_IDL);\n }\n return cached;\n}\n","import { Keypair, type Connection, type PublicKey, type Transaction } from \"@solana/web3.js\";\nimport {\n DynamicBondingCurveClient,\n deriveDbcPoolAddress,\n type PoolConfig,\n} from \"@meteora-ag/dynamic-bonding-curve-sdk\";\nimport { ACCESS_MODE } from \"../constants.js\";\nimport { createSaleInstruction, type PriceBandInput } from \"../instructions.js\";\nimport {\n PanguInputError,\n requireBigint,\n requireRealPublicKey,\n requireWholeNumber,\n} from \"../inputs.js\";\nimport { requireOneTransaction } from \"./budget.js\";\nimport { loadConfig, readyToSign } from \"./state.js\";\nimport { FORCED } from \"./template.js\";\n\n/** The sale's rules, as the issuer chooses them. */\nexport interface SaleTerms {\n /** Most raw token units one wallet may end up holding. */\n cap?: bigint;\n /** The same cap written as a share of what the curve sells. Use one or the other. */\n capShareBps?: number;\n accessMode: number;\n /** Access mode 2 only. */\n credential?: PublicKey;\n schema?: PublicKey;\n band?: PriceBandInput;\n /** Unix seconds at which the offering ends and every rule lifts. Leave out for no end. */\n endsAt?: number;\n}\n\nexport interface OpenSaleInput {\n connection: Connection;\n /** The pool's creator, who becomes the sale's issuer. Pays unless a payer is given. */\n creator: PublicKey;\n payer?: PublicKey;\n config: PublicKey;\n name: string;\n symbol: string;\n uri: string;\n sale: SaleTerms;\n /** The new token's mint. Generated when not given. It signs this transaction. */\n baseMint?: Keypair;\n /**\n * DBC's badge for a paying token that needs one, such as a tokenized stock.\n * Without it DBC refuses the pool with InvalidTokenBadge. The same badge the\n * launch template was opened with.\n */\n tokenBadge?: PublicKey;\n}\n\nexport interface OpenSale {\n transaction: Transaction;\n baseMint: Keypair;\n pool: PublicKey;\n bytes: number;\n}\n\n/**\n * A cap written as a share of the tokens the curve will sell before graduation.\n *\n * Taken from the template rather than from a number typed in, so the cap means\n * the same thing whatever supply the issuer chose. A share of 100 percent or\n * more is refused: create_sale answers CapCoversWholeSale for a cap at or above\n * the curve's supply, because one wallet could then buy the whole sale.\n */\nexport function capFromShare(swapBaseAmount: bigint, capShareBps: number): bigint {\n const amount = requireBigint(swapBaseAmount, \"swapBaseAmount\");\n if (typeof capShareBps === \"number\" && capShareBps >= 10_000) {\n throw new PanguInputError(\n `sale.capShareBps must be below 10000 (100 percent), got ${capShareBps}: a cap covering the whole curve lets one wallet buy everything, and the program refuses it`\n );\n }\n const bps = requireWholeNumber(capShareBps, \"sale.capShareBps\", 1, 9_999);\n const cap = (amount * BigInt(bps)) / 10_000n;\n if (cap <= 0n) {\n throw new PanguInputError(\n \"that share of this curve rounds down to no tokens at all, raise capShareBps\"\n );\n }\n return cap;\n}\n\nfunction capOf(terms: SaleTerms, config: PoolConfig): bigint {\n const hasCap = terms.cap !== undefined && terms.cap !== null;\n const hasShare = terms.capShareBps !== undefined && terms.capShareBps !== null;\n if (hasCap === hasShare) {\n throw new PanguInputError(\n \"a sale needs either cap or capShareBps, and never both, because they would disagree\"\n );\n }\n return hasCap\n ? requireBigint(terms.cap, \"sale.cap\")\n : capFromShare(BigInt(config.swapBaseAmount.toString()), terms.capShareBps as number);\n}\n\n/**\n * Opens the pool and the sale's rules in one transaction.\n *\n * C7: the rules and the hook's account list are derived from the mint, which is\n * public the moment the pool transaction is seen. Creating them in the same\n * transaction as the pool is what stops anyone else setting the rules for this\n * sale. Nothing is signed or sent here, and the transaction is measured, so a\n * sale that would not fit is refused before the creator signs.\n *\n * Throws PanguInputError when the template is not one Pangu opened, when the\n * cap is given twice or not at all, or when the transaction would not fit.\n */\nexport async function openSaleTransaction(\n input: OpenSaleInput\n): Promise<OpenSale> {\n const creator = requireRealPublicKey(input.creator, \"creator\");\n const payer = input.payer === undefined ? creator : requireRealPublicKey(input.payer, \"payer\");\n const config = requireRealPublicKey(input.config, \"config\");\n const accessMode = requireWholeNumber(input.sale?.accessMode, \"sale.accessMode\", 0, 2);\n\n const configState = await loadConfig(input.connection, config);\n if (configState.collectFeeMode !== FORCED.collectFeeMode) {\n throw new PanguInputError(\n \"this template collects fees in the sale token, which would move it past every cap. Open the template with launchTemplateTransaction.\"\n );\n }\n\n const cap = capOf(input.sale, configState);\n const baseMint = input.baseMint ?? Keypair.generate();\n const quoteMint = configState.quoteMint;\n const pool = deriveDbcPoolAddress(quoteMint, baseMint.publicKey, config);\n\n const client = new DynamicBondingCurveClient(input.connection, \"confirmed\");\n const transaction = await client.creator.createPoolWithTransferHook({\n baseMint: baseMint.publicKey,\n config,\n name: input.name,\n symbol: input.symbol,\n uri: input.uri,\n payer,\n poolCreator: creator,\n tokenBadge: input.tokenBadge,\n transferHookProgram: FORCED.transferHookProgram,\n });\n\n const band = input.sale.band;\n transaction.add(\n createSaleInstruction({\n issuer: creator,\n pool,\n mint: baseMint.publicKey,\n cap,\n accessMode,\n credential: accessMode === ACCESS_MODE.verifierCredential ? input.sale.credential : undefined,\n schema: accessMode === ACCESS_MODE.verifierCredential ? input.sale.schema : undefined,\n band,\n dbcConfig: config,\n quoteMint,\n endsAt: input.sale.endsAt,\n })\n );\n\n await readyToSign(input.connection, transaction, payer);\n return {\n transaction,\n baseMint,\n pool,\n bytes: requireOneTransaction(transaction, \"the pool and the sale's rules\"),\n };\n}\n","import { BN } from \"@anchor-lang/core\";\nimport {\n PublicKey,\n SystemProgram,\n TransactionInstruction,\n type AccountMeta,\n} from \"@solana/web3.js\";\nimport {\n buyerRecordAddress,\n extraAccountListAddress,\n feedIdBytes,\n priceFeedAddress,\n saleRulesAddress,\n type FeedId,\n} from \"./addresses.js\";\nimport { panguCoder } from \"./coder.js\";\nimport {\n ACCESS_MODE,\n LIMITS,\n PANGU_PROGRAM_ID,\n PANGU_SHARD_ID,\n} from \"./constants.js\";\nimport {\n PanguInputError,\n requireAbsent,\n requireBigint,\n requireRealPublicKey,\n requireWholeNumber,\n} from \"./inputs.js\";\n\n/** The ceiling a sale can put on the curve price, against the real stock's price. */\nexport interface PriceBandInput {\n /** How far above the live stock price a buy may leave the curve, in basis points. */\n bps: number;\n /** The Pyth feed carrying the stock price, as hex or 32 bytes. */\n priceFeedId: FeedId;\n /** Which Pyth shard to read. Defaults to Pangu's own, the one it refreshes. */\n shard?: number;\n /** How old the published price may be on a buy, in seconds. */\n maxPriceAgeSecs: number;\n /** The widest confidence interval this sale will buy against, in basis points. */\n maxConfBps: number;\n}\n\nexport interface CreateSaleInput {\n /** The pool's creator, who signs and pays. */\n issuer: PublicKey;\n /** The DBC hook pool, which must already exist. */\n pool: PublicKey;\n mint: PublicKey;\n /** Most raw token units one wallet may hold, net of sells. */\n cap: bigint;\n accessMode: number;\n /** Access mode 2 only: the verifier's credential and the schema that counts. */\n credential?: PublicKey;\n schema?: PublicKey;\n band?: PriceBandInput;\n /**\n * The DBC launch template this pool was opened on. Needed in every mode: the\n * program reads the fee mode off it before it will open a sale at all.\n */\n dbcConfig: PublicKey;\n /**\n * The token buyers pay in, the one the launch template names. Needed in every\n * mode: the program stores it, refuses one the issuer can freeze, and on a\n * banded sale reads its decimals and refuses wrapped SOL.\n */\n quoteMint: PublicKey;\n /**\n * Unix seconds at which the offering period ends and every rule lifts. Zero,\n * the default, means no end: the rules hold until graduation.\n */\n endsAt?: number;\n}\n\nexport interface OpenBuyerRecordInput {\n wallet: PublicKey;\n mint: PublicKey;\n}\n\nexport interface ApproveBuyerInput {\n issuer: PublicKey;\n mint: PublicKey;\n wallet: PublicKey;\n}\n\nexport type RevokeBuyerInput = ApproveBuyerInput;\n\nexport interface CloseBuyerRecordInput {\n wallet: PublicKey;\n mint: PublicKey;\n}\n\nconst ZERO_FEED = Array<number>(LIMITS.feedIdLength).fill(0);\n\n/** What the program stores for a sale with no band: every field zero. */\nconst NO_BAND = {\n band_bps: 0,\n price_account: PublicKey.default,\n price_feed_id: ZERO_FEED,\n price_shard: 0,\n max_price_age_secs: 0,\n max_conf_bps: 0,\n};\n\nfunction meta(\n pubkey: PublicKey,\n isSigner: boolean,\n isWritable: boolean\n): AccountMeta {\n return { pubkey, isSigner, isWritable };\n}\n\n/**\n * How Anchor says \"this optional account was not passed\": the program's own id\n * sits in its place. Leaving the slot out instead would shift every account\n * after it.\n */\nfunction absentAccount(): AccountMeta {\n return meta(PANGU_PROGRAM_ID, false, false);\n}\n\nfunction build(name: string, keys: AccountMeta[], args: object): TransactionInstruction {\n return new TransactionInstruction({\n programId: PANGU_PROGRAM_ID,\n keys,\n data: panguCoder().instruction.encode(name, args),\n });\n}\n\nfunction bandFields(band: PriceBandInput, field: string) {\n const bps = requireWholeNumber(\n band.bps,\n `${field}.bps`,\n LIMITS.minBandBps,\n LIMITS.maxBandBps\n );\n const priceFeedId = feedIdBytes(band.priceFeedId);\n if (priceFeedId.every((byte) => byte === 0)) {\n throw new PanguInputError(`${field}.priceFeedId of all zeros is not a feed`);\n }\n const shard =\n band.shard === undefined\n ? PANGU_SHARD_ID\n : requireWholeNumber(band.shard, `${field}.shard`, 0, LIMITS.maxShard);\n const maxPriceAgeSecs = requireWholeNumber(\n band.maxPriceAgeSecs,\n `${field}.maxPriceAgeSecs`,\n LIMITS.minPriceAgeSecs,\n LIMITS.maxPriceAgeSecs\n );\n const maxConfBps = requireWholeNumber(\n band.maxConfBps,\n `${field}.maxConfBps`,\n LIMITS.minConfBps,\n LIMITS.maxConfBps\n );\n\n return {\n band_bps: bps,\n // Derived here rather than asked for: the price account is the one program\n // address this shard and this feed id can produce under Pyth's price feed\n // program, and create_sale derives the same one and refuses anything else.\n price_account: priceFeedAddress(priceFeedId, shard),\n price_feed_id: Array.from(priceFeedId),\n price_shard: shard,\n max_price_age_secs: maxPriceAgeSecs,\n max_conf_bps: maxConfBps,\n };\n}\n\n/**\n * Opens a sale: stores the rules for a mint and publishes the account list the\n * transfer hook will be called with.\n *\n * The pool must already exist and the signer must be its creator. The pool's\n * launch template and the token buyers pay in are needed in every mode,\n * because the program reads the fee mode, the curve's supply and the paying\n * token before it will open a sale at all. Access mode 2 needs a credential and\n * a schema; a band needs the feed. Every input that could never pass on chain\n * and can be judged without reading the chain is refused here, with the same\n * limits the program holds.\n *\n * Throws PanguInputError. Sends nothing.\n */\nexport function createSaleInstruction(input: CreateSaleInput): TransactionInstruction {\n const issuer = requireRealPublicKey(input.issuer, \"issuer\");\n const pool = requireRealPublicKey(input.pool, \"pool\");\n const mint = requireRealPublicKey(input.mint, \"mint\");\n\n const cap = requireBigint(input.cap, \"cap\");\n if (cap <= 0n) {\n throw new PanguInputError(\"cap must be above zero, the program refuses a zero cap\");\n }\n if (cap > LIMITS.maxCap) {\n throw new PanguInputError(\"cap must fit in 64 bits\");\n }\n\n const accessMode = requireWholeNumber(input.accessMode, \"accessMode\", 0, 2);\n const wantsCredential = accessMode === ACCESS_MODE.verifierCredential;\n\n let credential = PublicKey.default;\n let schema = PublicKey.default;\n if (wantsCredential) {\n if (input.credential === undefined || input.schema === undefined) {\n throw new PanguInputError(\n \"access mode 2 needs both a credential and a schema, the program has nothing to check against without them\"\n );\n }\n credential = requireRealPublicKey(input.credential, \"credential\");\n schema = requireRealPublicKey(input.schema, \"schema\");\n } else {\n const reason = \"belongs to access mode 2, and the program refuses a sale that names it in any other mode\";\n requireAbsent(input.credential, \"credential\", reason);\n requireAbsent(input.schema, \"schema\", reason);\n }\n\n const dbcConfig = requireRealPublicKey(input.dbcConfig, \"dbcConfig\");\n\n const quoteMint = requireRealPublicKey(input.quoteMint, \"quoteMint\");\n const band =\n input.band !== undefined && input.band !== null\n ? bandFields(input.band, \"band\")\n : NO_BAND;\n const endsAt =\n input.endsAt === undefined\n ? 0\n : requireWholeNumber(input.endsAt, \"endsAt\", 0, Number.MAX_SAFE_INTEGER);\n\n const keys: AccountMeta[] = [\n meta(issuer, true, true),\n meta(pool, false, false),\n meta(mint, false, false),\n wantsCredential ? meta(credential, false, false) : absentAccount(),\n wantsCredential ? meta(schema, false, false) : absentAccount(),\n meta(dbcConfig, false, false),\n meta(quoteMint, false, false),\n meta(saleRulesAddress(mint), false, true),\n meta(extraAccountListAddress(mint), false, true),\n meta(SystemProgram.programId, false, false),\n ];\n\n return build(\"create_sale\", keys, {\n cap: new BN(cap.toString()),\n access_mode: accessMode,\n credential,\n schema,\n band,\n ends_at: new BN(endsAt),\n });\n}\n\n/**\n * Opens a wallet's own record, so a later buy has somewhere to count against.\n * A transfer hook cannot create accounts, which is why this comes first. Safe to\n * send twice.\n */\nexport function openBuyerRecordInstruction(\n input: OpenBuyerRecordInput\n): TransactionInstruction {\n const wallet = requireRealPublicKey(input.wallet, \"wallet\");\n const mint = requireRealPublicKey(input.mint, \"mint\");\n return build(\n \"open_buyer_record\",\n [\n meta(wallet, true, true),\n meta(mint, false, false),\n meta(saleRulesAddress(mint), false, false),\n meta(buyerRecordAddress(mint, wallet), false, true),\n meta(SystemProgram.programId, false, false),\n ],\n {}\n );\n}\n\n/**\n * Puts a wallet on the issuer's approved list, in access mode 1. Creates the\n * record if the wallet never opened one. Only the issuer named in the rules can\n * send it, and it never resets what the wallet has already bought.\n */\nexport function approveBuyerInstruction(\n input: ApproveBuyerInput\n): TransactionInstruction {\n const issuer = requireRealPublicKey(input.issuer, \"issuer\");\n const mint = requireRealPublicKey(input.mint, \"mint\");\n const wallet = requireRealPublicKey(input.wallet, \"wallet\");\n return build(\n \"approve_buyer\",\n [\n meta(issuer, true, true),\n meta(mint, false, false),\n meta(saleRulesAddress(mint), false, false),\n meta(buyerRecordAddress(mint, wallet), false, true),\n meta(SystemProgram.programId, false, false),\n ],\n { wallet }\n );\n}\n\n/**\n * Takes a wallet off the approved list. The wallet can still sell what it holds,\n * which is why the record is not closed.\n */\nexport function revokeBuyerInstruction(\n input: RevokeBuyerInput\n): TransactionInstruction {\n const issuer = requireRealPublicKey(input.issuer, \"issuer\");\n const mint = requireRealPublicKey(input.mint, \"mint\");\n const wallet = requireRealPublicKey(input.wallet, \"wallet\");\n return build(\n \"revoke_buyer\",\n [\n meta(issuer, true, false),\n meta(mint, false, false),\n meta(saleRulesAddress(mint), false, false),\n meta(buyerRecordAddress(mint, wallet), false, true),\n ],\n { wallet }\n );\n}\n\n/**\n * Closes a wallet's record and returns the rent.\n *\n * A record with nothing left in it closes at any time, mid-sale included, since\n * it holds no count anybody could lose. A record that still counts tokens waits\n * for the sale to finish, which is the moment the mint stops naming Pangu as its\n * hook or the offering period in the rules ends; until then the program answers\n * SaleStillRunning. Reopening later is safe, and in the issuer-list mode the\n * wallet has to be approved again.\n */\nexport function closeBuyerRecordInstruction(\n input: CloseBuyerRecordInput\n): TransactionInstruction {\n const wallet = requireRealPublicKey(input.wallet, \"wallet\");\n const mint = requireRealPublicKey(input.mint, \"mint\");\n return build(\n \"close_buyer_record\",\n [\n meta(wallet, true, true),\n meta(mint, false, false),\n meta(buyerRecordAddress(mint, wallet), false, true),\n meta(saleRulesAddress(mint), false, false),\n ],\n {}\n );\n}\n","import {\n SystemProgram,\n type Connection,\n type PublicKey,\n type Transaction,\n type TransactionInstruction,\n} from \"@solana/web3.js\";\nimport { BN } from \"@anchor-lang/core\";\nimport {\n NATIVE_MINT,\n createAssociatedTokenAccountIdempotentInstruction,\n createSyncNativeInstruction,\n getAssociatedTokenAddressSync,\n} from \"@solana/spl-token\";\nimport { SwapMode } from \"@meteora-ag/dynamic-bonding-curve-sdk\";\nimport { buyerRecordAddress } from \"../addresses.js\";\nimport { TOKEN_2022_PROGRAM_ID } from \"../constants.js\";\nimport { openBuyerRecordInstruction } from \"../instructions.js\";\nimport { PanguInputError, requireBigint, requireRealPublicKey, requireWholeNumber } from \"../inputs.js\";\nimport { COMPUTE_LIMIT, computeLimit, requireOneTransaction } from \"./budget.js\";\nimport { quoteExactIn, quotePartialFill } from \"./quote.js\";\nimport { hookAccounts, hookAccountsInfo, type PendingTokenAccount } from \"./hook.js\";\nimport {\n DBC_POOL_AUTHORITY,\n dbcProgram,\n loadPool,\n loadSellPool,\n readyToSign,\n type PoolMarket,\n} from \"./state.js\";\n\n/** A trade, built but not signed. */\nexport interface TradeTransaction {\n transaction: Transaction;\n /** What Meteora's own quote says this trade returns, in raw units. */\n expectedAmountOut: bigint;\n /** The least the trade may return before it is refused, after slippage. */\n minimumAmountOut: bigint;\n bytes: number;\n computeUnitLimit: number;\n}\n\nexport interface BuyInput {\n connection: Connection;\n buyer: PublicKey;\n mint: PublicKey;\n /** Raw units of the paying token to spend. */\n amountIn: bigint;\n slippageBps?: number;\n /**\n * How to handle a curve with less left than this buy asks for.\n *\n * \"exactIn\", the default, spends the whole amount or the trade is refused.\n * \"partial\" lets DBC take what the curve can still absorb and leave the rest\n * in the buyer's account. The last buy of a sale needs \"partial\": the tokens\n * run out before the paying side does, and an exact-in swap is refused.\n */\n fill?: \"exactIn\" | \"partial\";\n /**\n * The fewest sale tokens, in raw units, the buy may return before the chain\n * refuses it. Set it from the quote the buyer was shown, less their slippage,\n * so the floor is what they agreed to and not a fresh quote taken at build\n * time. When given it replaces `slippageBps`, and the build throws if its own\n * fresh quote already returns less.\n */\n minimumAmountOut?: bigint;\n}\n\nexport interface SellInput {\n connection: Connection;\n seller: PublicKey;\n mint: PublicKey;\n /** Raw units of the sale token to sell back to the pool. */\n amountIn: bigint;\n slippageBps?: number;\n /**\n * The fewest paying tokens, in raw units, the sell may return before the\n * chain refuses it. The same rule as `minimumAmountOut` on a buy.\n */\n minimumQuoteOut?: bigint;\n}\n\nconst DEFAULT_SLIPPAGE_BPS = 100;\n\n/**\n * One swap through the hook, built by hand.\n *\n * The Meteora SDK's own `swap2WithTransferHook` resolves a hook's extra\n * accounts against placeholder token accounts, which cannot work for a hook\n * that derives a buyer's record from the real receiver. So the same on-chain\n * instruction is built here and the accounts come from Pangu's published list.\n * See finding 1 in docs/measurements/fork-test.md.\n */\nasync function buildSwap(options: {\n connection: Connection;\n view: PoolMarket;\n owner: PublicKey;\n swapBaseForQuote: boolean;\n amountIn: bigint;\n slippageBps: number;\n action: string;\n fill?: \"exactIn\" | \"partial\";\n /** The caller's own floor, which wins over the one worked out here. */\n floor?: bigint;\n}): Promise<TradeTransaction> {\n const { connection, view, owner, swapBaseForQuote, amountIn } = options;\n const partial = options.fill === \"partial\";\n const quote = partial\n ? quotePartialFill(view, swapBaseForQuote, amountIn, options.slippageBps)\n : quoteExactIn(view, swapBaseForQuote, amountIn, options.slippageBps);\n const quoted = BigInt(quote.outputAmount.toString());\n if (options.floor !== undefined && quoted < options.floor) {\n throw new PanguInputError(\n `the market moved: ${options.action} now returns ${quoted} raw units, below the floor of ${options.floor}. Take a fresh quote`\n );\n }\n // A partial fill takes an unknown share of the input, so a floor worked out\n // from the whole of it would refuse the trade. The curve itself is the floor,\n // unless the caller set one from the partial quote it showed.\n const minimumAmountOut =\n options.floor ??\n (partial ? 0n : BigInt((quote.minimumAmountOut ?? 0n).toString()));\n\n const quoteAta = getAssociatedTokenAddressSync(\n view.quoteMint,\n owner,\n false,\n view.quoteProgram\n );\n const baseAta = getAssociatedTokenAddressSync(\n view.baseMint,\n owner,\n false,\n TOKEN_2022_PROGRAM_ID\n );\n\n const pre: TransactionInstruction[] = [computeLimit(COMPUTE_LIMIT.swap)];\n const pending: PendingTokenAccount[] = [];\n\n // The paying token account is opened either way: it receives on a sell and\n // pays on a buy, and idempotent means a second buy costs nothing extra.\n pre.push(\n createAssociatedTokenAccountIdempotentInstruction(\n owner,\n quoteAta,\n owner,\n view.quoteMint,\n view.quoteProgram\n )\n );\n\n if (!swapBaseForQuote) {\n const baseAccount = await connection.getAccountInfo(baseAta);\n if (baseAccount === null) {\n pre.push(\n createAssociatedTokenAccountIdempotentInstruction(\n owner,\n baseAta,\n owner,\n view.baseMint,\n TOKEN_2022_PROGRAM_ID\n )\n );\n pending.push({ address: baseAta, mint: view.baseMint, owner });\n }\n if (view.quoteMint.equals(NATIVE_MINT)) {\n pre.push(\n SystemProgram.transfer({\n fromPubkey: owner,\n toPubkey: quoteAta,\n lamports: amountIn,\n }),\n createSyncNativeInstruction(quoteAta, view.quoteProgram)\n );\n }\n // A transfer hook cannot create accounts, so the record has to exist before\n // the buy. Sending it again would fail, so it only goes in when missing.\n const record = await connection.getAccountInfo(\n buyerRecordAddress(view.baseMint, owner)\n );\n if (record === null) {\n pre.push(openBuyerRecordInstruction({ wallet: owner, mint: view.baseMint }));\n }\n }\n\n const hook = await hookAccounts({\n connection,\n mint: view.baseMint,\n source: swapBaseForQuote ? baseAta : view.baseVault,\n destination: swapBaseForQuote ? view.baseVault : baseAta,\n authority: swapBaseForQuote ? owner : DBC_POOL_AUTHORITY,\n amount: swapBaseForQuote ? amountIn : BigInt(quote.outputAmount.toString()),\n pending,\n });\n\n const transaction = await dbcProgram(connection)\n .methods.swap2WithTransferHook(\n {\n amount0: new BN(amountIn.toString()),\n amount1: new BN(minimumAmountOut.toString()),\n swapMode: partial ? SwapMode.PartialFill : SwapMode.ExactIn,\n },\n hookAccountsInfo(hook)\n )\n .accountsPartial({\n poolAuthority: DBC_POOL_AUTHORITY,\n config: view.config,\n pool: view.pool,\n inputTokenAccount: swapBaseForQuote ? baseAta : quoteAta,\n outputTokenAccount: swapBaseForQuote ? quoteAta : baseAta,\n baseVault: view.baseVault,\n quoteVault: view.quoteVault,\n baseMint: view.baseMint,\n quoteMint: view.quoteMint,\n payer: owner,\n tokenBaseProgram: TOKEN_2022_PROGRAM_ID,\n tokenQuoteProgram: view.quoteProgram,\n referralTokenAccount: null,\n })\n .remainingAccounts(hook)\n .preInstructions(pre)\n .transaction();\n\n await readyToSign(connection, transaction, owner);\n return {\n transaction,\n expectedAmountOut: quoted,\n minimumAmountOut,\n bytes: requireOneTransaction(transaction, options.action),\n computeUnitLimit: COMPUTE_LIMIT.swap,\n };\n}\n\nfunction slippageOf(value: number | undefined): number {\n return value === undefined\n ? DEFAULT_SLIPPAGE_BPS\n : requireWholeNumber(value, \"slippageBps\", 0, 10_000);\n}\n\nfunction floorOf(value: unknown, field: string): bigint | undefined {\n if (value === undefined) {\n return undefined;\n }\n const floor = requireBigint(value, field);\n if (floor < 0n) {\n throw new PanguInputError(`${field} must not be below zero`);\n }\n return floor;\n}\n\nfunction amountOf(value: unknown, field: string): bigint {\n const amount = requireBigint(value, field);\n if (amount <= 0n) {\n throw new PanguInputError(`${field} must be above zero`);\n }\n return amount;\n}\n\n/**\n * Buys into a sale: the buyer's paying token in, the sale token out.\n *\n * Everything the hook needs travels with it. The paying token account is opened\n * if missing, wrapped SOL is funded, the buyer's record is opened when this is\n * their first buy, and the hook's accounts come from the sale's own published\n * list, so a credential sale and a banded sale carry their extra accounts\n * without the caller knowing they exist. Nothing is signed or sent.\n *\n * Throws PanguInputError for a mint with no Pangu sale, an amount of zero, a\n * transaction that would not fit, or a `minimumAmountOut` the market has\n * already moved past.\n */\nexport async function buyTransaction(input: BuyInput): Promise<TradeTransaction> {\n const buyer = requireRealPublicKey(input.buyer, \"buyer\");\n const amountIn = amountOf(input.amountIn, \"amountIn\");\n const floor = floorOf(input.minimumAmountOut, \"minimumAmountOut\");\n const view = await loadPool(input.connection, input.mint);\n return buildSwap({\n connection: input.connection,\n view,\n owner: buyer,\n swapBaseForQuote: false,\n amountIn,\n slippageBps: slippageOf(input.slippageBps),\n action: \"the buy\",\n fill: input.fill ?? \"exactIn\",\n floor,\n });\n}\n\n/**\n * Sells back to the pool: the sale token in, the paying token out.\n *\n * The exit reads nothing that can be missing, which is C5 in the threat model,\n * so a seller who is no longer approved, or whose sale's price feed has gone\n * stale, still gets out. That includes a sale whose rules this package cannot\n * read, because an older build wrote them: the program lets that sell through,\n * so the pool is found from the mint instead and the sell is built all the\n * same. Nothing is signed or sent.\n *\n * Throws PanguInputError when no transfer hook pool sells the mint, for an\n * amount of zero, for a transaction that would not fit, or for a\n * `minimumQuoteOut` the market has already moved past.\n */\nexport async function sellTransaction(input: SellInput): Promise<TradeTransaction> {\n const seller = requireRealPublicKey(input.seller, \"seller\");\n const amountIn = amountOf(input.amountIn, \"amountIn\");\n const floor = floorOf(input.minimumQuoteOut, \"minimumQuoteOut\");\n const view = await loadSellPool(input.connection, input.mint);\n return buildSwap({\n connection: input.connection,\n view,\n owner: seller,\n swapBaseForQuote: true,\n amountIn,\n slippageBps: slippageOf(input.slippageBps),\n action: \"the sell\",\n floor,\n });\n}\n","import { BN } from \"@anchor-lang/core\";\nimport {\n swapQuoteExactIn,\n swapQuoteExactOut,\n swapQuotePartialFill,\n} from \"@meteora-ag/dynamic-bonding-curve-sdk\";\nimport type { PoolMarket } from \"./state.js\";\n\n/**\n * The numbers Meteora's quote functions really return.\n *\n * Their published type, `SwapQuote2Result`, resolves to an empty object here\n * because it is built from an Anchor IDL lookup that TypeScript cannot follow\n * through their bundle, so the fields are written out. Every one is checked\n * against their own source (`swapQuoteExactIn` and `swapQuoteExactOut` in\n * dynamic-bonding-curve-sdk 1.5.12) and read only through `toString`, so no\n * copy of bn.js has to match.\n */\nexport interface SwapNumbers {\n /** What the trade returns, in raw units of the token coming out. */\n outputAmount: { toString(): string };\n /** Partial fill only: the part of the input the curve cannot take. */\n amountLeft?: { toString(): string };\n /** Where this trade leaves the curve, as DBC's Q64.64 square root price. */\n nextSqrtPrice: { toString(): string };\n /** Exact-in only: the floor after slippage. */\n minimumAmountOut?: { toString(): string };\n /** Exact-out only: the ceiling after slippage. */\n maximumAmountIn?: { toString(): string };\n}\n\n/** What this much of the paying token, or of the sale token, would return. */\nexport function quoteExactIn(\n view: PoolMarket,\n swapBaseForQuote: boolean,\n amountIn: bigint,\n slippageBps: number\n): SwapNumbers {\n return swapQuoteExactIn(\n view.poolAccount,\n view.configState,\n swapBaseForQuote,\n new BN(amountIn.toString()),\n slippageBps,\n false,\n view.currentPoint,\n // The template Pangu builds leaves the first swap minimum fee off, and\n // loadPool refuses a template that turns it on.\n false\n ) as unknown as SwapNumbers;\n}\n\n/** What it would take to end up with this many tokens, and where that lands the curve. */\nexport function quoteExactOut(\n view: PoolMarket,\n swapBaseForQuote: boolean,\n amountOut: bigint,\n slippageBps: number\n): SwapNumbers {\n return swapQuoteExactOut(\n view.poolAccount,\n view.configState,\n swapBaseForQuote,\n new BN(amountOut.toString()),\n slippageBps,\n false,\n view.currentPoint,\n false\n ) as unknown as SwapNumbers;\n}\n\n/**\n * What this much would buy when the curve may run out partway through.\n *\n * This is the quote behind the buy that completes a sale: DBC takes as much of\n * the input as the curve can still absorb and leaves the rest. Exact-in refuses\n * that trade outright, which is why the last buyer of every sale needs this.\n */\nexport function quotePartialFill(\n view: PoolMarket,\n swapBaseForQuote: boolean,\n amountIn: bigint,\n slippageBps: number\n): SwapNumbers {\n return swapQuotePartialFill(\n view.poolAccount,\n view.configState,\n swapBaseForQuote,\n new BN(amountIn.toString()),\n slippageBps,\n false,\n view.currentPoint,\n false\n ) as unknown as SwapNumbers;\n}\n","import { Buffer } from \"buffer\";\nimport type { AccountInfo, AccountMeta, Connection, PublicKey } from \"@solana/web3.js\";\nimport {\n createExecuteInstruction,\n getExtraAccountMetas,\n resolveExtraAccountMeta,\n} from \"@solana/spl-token\";\nimport { AccountsType } from \"@meteora-ag/dynamic-bonding-curve-sdk\";\nimport { extraAccountListAddress } from \"../addresses.js\";\nimport { PANGU_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from \"../constants.js\";\nimport { PanguInputError } from \"../inputs.js\";\n\n/**\n * A token account this transaction creates before the swap runs.\n *\n * Pangu derives a buyer's record from the owner field inside the receiving\n * token account, so resolving the hook's accounts means reading that account.\n * On a first buy it does not exist yet, and the chain cannot answer for it. The\n * owner is not a guess though: the same transaction creates the account, so the\n * bytes are filled in here from what is about to be written.\n */\nexport interface PendingTokenAccount {\n address: PublicKey;\n mint: PublicKey;\n owner: PublicKey;\n}\n\n/** The first 64 bytes of a token account: the mint, then the owner. */\nfunction tokenAccountBytes(mint: PublicKey, owner: PublicKey): Buffer {\n const data = Buffer.alloc(165);\n mint.toBuffer().copy(data, 0);\n owner.toBuffer().copy(data, 32);\n return data;\n}\n\nfunction chainPlusPending(\n connection: Connection,\n pending: PendingTokenAccount[]\n): Connection {\n if (pending.length === 0) {\n return connection;\n }\n const known = new Map(\n pending.map((account) => [\n account.address.toBase58(),\n {\n data: tokenAccountBytes(account.mint, account.owner),\n owner: TOKEN_2022_PROGRAM_ID,\n executable: false,\n lamports: 0,\n rentEpoch: 0,\n } as AccountInfo<Buffer>,\n ])\n );\n const reader = {\n getAccountInfo: async (address: PublicKey) =>\n known.get(address.toBase58()) ?? (await connection.getAccountInfo(address)),\n };\n // The resolver only ever calls getAccountInfo. Handing it this reader is what\n // lets a first buy resolve the record of an account the transaction is still\n // about to open.\n return reader as unknown as Connection;\n}\n\nexport interface HookAccountsInput {\n connection: Connection;\n mint: PublicKey;\n /** The token account the sale token leaves. */\n source: PublicKey;\n /** The token account the sale token lands in. */\n destination: PublicKey;\n /** Whoever signs for the source account. */\n authority: PublicKey;\n amount: bigint;\n pending?: PendingTokenAccount[];\n}\n\n/**\n * The accounts Pangu's hook has to be called with, read from the list the\n * program itself published on chain.\n *\n * Nothing here is a copy of what the program writes. The list is fetched, each\n * entry is resolved against the real token accounts of this transfer, and the\n * caller gets whatever that sale needs: a plain sale's four, a credential\n * sale's seven, a banded sale's eleven. The Meteora SDK's own helper cannot do\n * this because it resolves against placeholder accounts, and a record derived\n * from the receiver's owner has nothing to read there. See finding 1 in\n * docs/measurements/fork-test.md.\n *\n * Order matters and is the one Token-2022 rebuilds on chain: the published list\n * itself, then its entries, then the hook program.\n *\n * Throws PanguInputError when the mint has no published list, which means it is\n * not a Pangu sale.\n */\nexport async function hookAccounts(\n input: HookAccountsInput\n): Promise<AccountMeta[]> {\n const validation = extraAccountListAddress(input.mint);\n const listAccount = await input.connection.getAccountInfo(validation);\n if (listAccount === null) {\n throw new PanguInputError(\n `${input.mint.toBase58()} has no published Pangu account list, so it is not a running Pangu sale`\n );\n }\n\n const execute = createExecuteInstruction(\n PANGU_PROGRAM_ID,\n input.source,\n input.mint,\n input.destination,\n input.authority,\n validation,\n input.amount\n );\n const reader = chainPlusPending(input.connection, input.pending ?? []);\n\n for (const meta of getExtraAccountMetas(listAccount)) {\n execute.keys.push(\n await resolveExtraAccountMeta(\n reader,\n meta,\n execute.keys,\n execute.data,\n PANGU_PROGRAM_ID\n )\n );\n }\n\n return [\n { pubkey: validation, isSigner: false, isWritable: false },\n ...execute.keys.slice(5),\n { pubkey: PANGU_PROGRAM_ID, isSigner: false, isWritable: false },\n ];\n}\n\n/** DBC has to be told how many of the remaining accounts belong to the hook. */\nexport function hookAccountsInfo(accounts: AccountMeta[]) {\n return {\n slices: [\n { accountsType: AccountsType.TransferHookBase, length: accounts.length },\n ],\n };\n}\n","import { SYSVAR_CLOCK_PUBKEY, type Connection, type PublicKey } from \"@solana/web3.js\";\nimport type { Sale } from \"../accounts.js\";\nimport { getBuyerRecord } from \"../accounts.js\";\nimport { attestationAddress } from \"../addresses.js\";\nimport { curvePriceDollars, priceCeiling } from \"../band.js\";\nimport { ACCESS_MODE } from \"../constants.js\";\nimport { explainPanguError, type PanguErrorName } from \"../errors.js\";\nimport { PanguInputError, requireBigint, requireRealPublicKey } from \"../inputs.js\";\nimport { readPrice, type PriceReading } from \"../feed.js\";\nimport { credentialRefusal } from \"./credential.js\";\nimport { quoteExactOut } from \"./quote.js\";\nimport { loadPool } from \"./state.js\";\n\n/** What the chain says about a buy that has not been signed yet. */\nexport interface BuyPreflight {\n ok: boolean;\n /** The program's own refusal this buy would hit, or null when it would pass. */\n error: PanguErrorName | null;\n /** One sentence a buyer can read. Null when the buy would pass. */\n reason: string | null;\n /** Raw token units this wallet may still buy before the cap stops it. */\n capRoom: bigint;\n /** Where this buy would leave the curve, in dollars scaled by 1e18. */\n curvePrice: bigint | null;\n /** The highest curve price the band allows right now, same scale. */\n ceiling: bigint | null;\n /** The sale's live stock price, when it has a band. */\n price: PriceReading | null;\n /**\n * True when the wallet has no record yet and the caller said the buy opens\n * one in the same transaction, so every answer above assumes a fresh record:\n * unapproved, nothing bought. `buyTransaction` always does that.\n */\n recordOpensInThisBuy: boolean;\n}\n\nfunction refused(\n error: PanguErrorName,\n capRoom: bigint,\n extra: Partial<BuyPreflight> = {}\n): BuyPreflight {\n return {\n ok: false,\n error,\n reason: explainPanguError(error),\n capRoom,\n curvePrice: null,\n ceiling: null,\n price: null,\n recordOpensInThisBuy: false,\n ...extra,\n };\n}\n\nexport interface PreflightBuyInput {\n connection: Connection;\n buyer: PublicKey;\n mint: PublicKey;\n /** Raw units of the sale token the buyer wants to end up with. */\n amountOut: bigint;\n /**\n * Set when the buy will open the wallet's record in the same transaction, as\n * `buyTransaction` does on a first buy. A missing record is then judged as\n * the fresh one that transaction creates instead of being refused, so a first\n * buyer gets the band and the cap answers. Off by default, which refuses a\n * missing record with BuyerRecordMissing as the hook would on its own.\n */\n openingRecord?: boolean;\n}\n\n/**\n * Says whether a buy would be refused, and why, before anything is signed.\n *\n * Runs the hook's own checks in the hook's own order against live chain state:\n * the record, the approval or the credential, the price band, then the cap.\n * The order is the hook's and not a tidier one, because a buy that breaks two\n * rules at once has to be given the same refusal here that the chain would\n * give it, and handle_execute judges the band before the cap.\n *\n * In mode 2 the attestation and the credential's list of authorized signers are\n * decoded here the way the hook decodes them, so a wallet is told whether its\n * approval is missing, out of date, or signed by a key the verifier has since\n * dropped. The answer is one of the program's error names with its plain\n * sentence, so the app can say the same thing before and after a refusal.\n *\n * With `openingRecord` a wallet with no record is judged as the record the buy\n * opens would leave it: not approved, nothing bought, so an issuer-list sale\n * still answers NotApproved and every other sale goes on to the band and the\n * cap with the whole cap as room.\n *\n * What it cannot see: the Wormhole guardian signatures behind the price, which\n * only Pyth's receiver program can check, and anything that changes between\n * this read and the buy landing. A \"pass\" here is the state now, not a promise.\n *\n * Throws PanguInputError for a mint with no Pangu sale.\n */\nexport async function preflightBuy(\n input: PreflightBuyInput\n): Promise<BuyPreflight> {\n const buyer = requireRealPublicKey(input.buyer, \"buyer\");\n const amountOut = requireBigint(input.amountOut, \"amountOut\");\n if (amountOut <= 0n) {\n throw new PanguInputError(\"amountOut must be above zero\");\n }\n\n const openingRecord = input.openingRecord === true;\n\n const view = await loadPool(input.connection, input.mint);\n const sale = view.sale;\n const existing = await getBuyerRecord(input.connection, sale.mint, buyer);\n\n if (existing === null && !openingRecord) {\n return refused(\"BuyerRecordMissing\", sale.cap);\n }\n const recordOpensInThisBuy = existing === null;\n // What open_buyer_record writes: this wallet, not approved, nothing bought.\n const record = existing ?? { approved: false, netBought: 0n };\n const capRoom = max(sale.cap - record.netBought, 0n);\n const opened = { recordOpensInThisBuy };\n\n if (sale.accessMode === ACCESS_MODE.issuerList && !record.approved) {\n return refused(\"NotApproved\", capRoom, opened);\n }\n if (sale.accessMode === ACCESS_MODE.verifierCredential) {\n const refusal = await credentialCheck(input.connection, sale, buyer);\n if (refusal !== null) {\n return refused(refusal, capRoom, opened);\n }\n }\n\n let price: PriceReading | null = null;\n let curvePrice: bigint | null = null;\n let ceiling: bigint | null = null;\n\n if (sale.hasBand) {\n price = await readPrice(input.connection, sale);\n if (!price.usable) {\n return refused(price.error ?? \"PriceStale\", capRoom, { price, ...opened });\n }\n\n // Where this buy would leave the curve, from Meteora's own exact-out quote,\n // against the ceiling the band puts on it. Both roundings match the program's.\n const quote = quoteExactOut(view, false, amountOut, 0);\n curvePrice = curvePriceDollars(\n BigInt(quote.nextSqrtPrice.toString()),\n sale.baseDecimals,\n sale.quoteDecimals\n );\n ceiling = priceCeiling(sale, price.price);\n if (curvePrice > ceiling) {\n return refused(\"PriceOutsideBand\", capRoom, { curvePrice, ceiling, price, ...opened });\n }\n }\n\n if (amountOut > capRoom) {\n return refused(\"OverCap\", capRoom, { curvePrice, ceiling, price, ...opened });\n }\n\n return {\n ok: true,\n error: null,\n reason: null,\n capRoom,\n curvePrice,\n ceiling,\n price,\n recordOpensInThisBuy,\n };\n}\n\nfunction max(a: bigint, b: bigint): bigint {\n return a > b ? a : b;\n}\n\n/** Where the Clock sysvar keeps its Unix time: slot, epoch start, epoch, schedule. */\nconst CLOCK_UNIX_TIMESTAMP_OFFSET = 32;\n\n/**\n * Reads the credential, the attestation and the chain's clock in one call, then\n * asks the same question the hook asks.\n *\n * The time comes from the Clock sysvar rather than this machine, because that is\n * the clock the hook compares an expiry against and a laptop can be minutes out.\n * If the sysvar cannot be read, this machine's clock stands in, which can only\n * misjudge an expiry within that drift.\n */\nasync function credentialCheck(\n connection: Connection,\n sale: Sale,\n buyer: PublicKey\n): Promise<PanguErrorName | null> {\n const read = await connection.getMultipleAccountsInfo([\n sale.credential,\n attestationAddress(sale.credential, sale.schema, buyer),\n SYSVAR_CLOCK_PUBKEY,\n ]);\n const credential = read[0] ?? null;\n const attestation = read[1] ?? null;\n const clock = read[2] ?? null;\n\n const stamp =\n clock !== null && clock.data.length >= CLOCK_UNIX_TIMESTAMP_OFFSET + 8\n ? Number(clock.data.readBigInt64LE(CLOCK_UNIX_TIMESTAMP_OFFSET))\n : Math.floor(Date.now() / 1000);\n\n return credentialRefusal(sale, buyer, {\n credential:\n credential === null ? null : { owner: credential.owner, data: credential.data },\n attestation:\n attestation === null ? null : { owner: attestation.owner, data: attestation.data },\n now: stamp,\n });\n}\n","import { LIMITS } from \"./constants.js\";\nimport { PanguInputError, requireBigint, requireWholeNumber } from \"./inputs.js\";\n\n/**\n * Every price in this package is a dollar amount scaled by 1e18, which is the\n * one scale the program compares on (PRICE_SCALE_DECIMALS in price.rs).\n * Working in that scale means the band comparison never rounds twice.\n */\nexport const DOLLAR_SCALE = 10n ** 18n;\n\nfunction pow10(exponent: number): bigint {\n return 10n ** BigInt(exponent);\n}\n\n/**\n * Pyth's exponent range this package can read: an equity is published at -5 and\n * a tokenised one at -8. Source: MIN_EXPONENT and MAX_EXPONENT in price.rs.\n */\nconst MIN_EXPONENT = -18;\nconst MAX_EXPONENT = 0;\n\n/**\n * A Pyth price turned into dollars scaled by 1e18, the way\n * `stock_price_1e18` does it on chain.\n *\n * Pyth publishes a whole number and an exponent, and the real price is the\n * number times ten to that exponent. A price at a finer scale than 1e18 rounds\n * down, exactly as the program's integer division does, and a zero is what the\n * program then refuses.\n *\n * Throws PanguInputError for a price that is not above zero, or an exponent no\n * dollar price can use.\n */\nexport function stockPriceDollars(price: bigint, exponent: number): bigint {\n const raw = requireBigint(price, \"price\");\n if (raw <= 0n) {\n throw new PanguInputError(\"a price of zero or less is not a price\");\n }\n const power = requireWholeNumber(exponent, \"exponent\", MIN_EXPONENT, MAX_EXPONENT);\n const shift = 18 + power;\n return shift >= 0 ? raw * pow10(shift) : raw / pow10(-shift);\n}\n\n/**\n * Pyth's confidence interval as basis points of the price itself, rounded UP.\n *\n * Rounded up, so half a basis point of doubt counts as one and never as none.\n * The same arithmetic as `require_confidence` in price.rs.\n *\n * Throws PanguInputError for a price that is not above zero.\n */\nexport function confidenceBps(price: bigint, conf: bigint): bigint {\n const raw = requireBigint(price, \"price\");\n const doubt = requireBigint(conf, \"conf\");\n if (raw <= 0n) {\n throw new PanguInputError(\"a price of zero or less has no confidence ratio\");\n }\n if (doubt < 0n) {\n throw new PanguInputError(\"a confidence interval cannot be negative\");\n }\n return (doubt * 10_000n + raw - 1n) / raw;\n}\n\n/**\n * The curve's price in dollars per whole token, scaled by 1e18 and rounded UP.\n *\n * `sqrtPrice` is DBC's Q64.64 square root of quote raw units per base raw unit,\n * so the price is `(sqrtPrice / 2^64)^2` shifted by the two mints' decimals.\n * Rounding goes up, always, matching `curve_price_ceil_1e18` in\n * programs/pangu/src/price.rs, so a fraction of a unit can never be the reason\n * a buy looks allowed here and is refused on chain.\n *\n * Throws PanguInputError for a negative square root price or for decimals past\n * the program's own limit of 18.\n */\nexport function curvePriceDollars(\n sqrtPrice: bigint,\n baseDecimals: number,\n quoteDecimals: number\n): bigint {\n const root = requireBigint(sqrtPrice, \"sqrtPrice\");\n if (root < 0n) {\n throw new PanguInputError(\"sqrtPrice cannot be negative\");\n }\n const base = requireWholeNumber(baseDecimals, \"baseDecimals\", 0, LIMITS.maxDecimals);\n const quote = requireWholeNumber(\n quoteDecimals,\n \"quoteDecimals\",\n 0,\n LIMITS.maxDecimals\n );\n\n const numerator = root * root * pow10(18 + base);\n const denominator = (1n << 128n) * pow10(quote);\n const whole = numerator / denominator;\n return numerator % denominator === 0n ? whole : whole + 1n;\n}\n\n/** The part of a sale's rules the ceiling is worked out from. */\nexport interface BandRules {\n bandBps: number;\n}\n\n/**\n * The highest curve price this sale allows, scaled by 1e18 and rounded DOWN.\n *\n * Rounding down here and up in `curvePriceDollars` is the program's own pairing\n * (`band_ceiling_floor_1e18`): a buy that lands exactly on the ceiling passes,\n * and nothing between the two roundings slips through.\n *\n * Throws PanguInputError when the sale has no band or the stock price is not\n * above zero, which is what the program treats as an unusable price.\n */\nexport function priceCeiling(sale: BandRules, stockPrice: bigint): bigint {\n const bandBps = requireWholeNumber(\n sale?.bandBps,\n \"sale.bandBps\",\n 1,\n LIMITS.maxBandBps\n );\n const price = requireBigint(stockPrice, \"stockPrice\");\n if (price <= 0n) {\n throw new PanguInputError(\n \"a stock price of zero or less is never a ceiling, the program refuses it\"\n );\n }\n return (price * BigInt(10_000 + bandBps)) / 10_000n;\n}\n\n/** The same 1e18 scaled number as dollars, for display only. */\nexport function dollars(scaled: bigint): number {\n return Number(scaled) / Number(DOLLAR_SCALE);\n}\n","import { PANGU_IDL, PANGU_PROGRAM_ID } from \"./constants.js\";\n\n/** One of the program's own refusals, matched out of a transaction's logs. */\nexport interface PanguError {\n code: number;\n name: PanguErrorName;\n /** The program's own message, as written in the IDL. */\n message: string;\n}\n\ninterface IdlError {\n code: number;\n name: string;\n msg?: string;\n}\n\nconst idlErrors = (PANGU_IDL as unknown as { errors?: IdlError[] }).errors ?? [];\n\n/**\n * Every error the program can return, read straight out of the IDL so a new one\n * cannot be missed here.\n */\nexport const PANGU_ERRORS: readonly PanguError[] = Object.freeze(\n idlErrors.map((error) => ({\n code: error.code,\n name: error.name as PanguErrorName,\n message: error.msg ?? error.name,\n }))\n);\n\nconst byCode = new Map(PANGU_ERRORS.map((error) => [error.code, error]));\nconst byName = new Map(PANGU_ERRORS.map((error) => [error.name as string, error]));\n\nconst PANGU = PANGU_PROGRAM_ID.toBase58();\n\nconst INVOKE = /^Program (\\S+) invoke \\[\\d+\\]$/;\nconst SUCCESS = /^Program (\\S+) success$/;\nconst FAILED = /^Program (\\S+) failed: (.*)$/;\nconst ERROR_NAME = /Error Code: ([A-Za-z0-9_]+)/;\nconst ERROR_NUMBER = /Error Number: (\\d+)/;\nconst CUSTOM = /custom program error: (0x[0-9a-fA-F]+|\\d+)/;\n\nfunction toCode(text: string): number {\n return text.startsWith(\"0x\") || text.startsWith(\"0X\")\n ? Number.parseInt(text.slice(2), 16)\n : Number.parseInt(text, 10);\n}\n\n/** The refusal a log line names, by name, then by number, then by bare code. */\nfunction refusalIn(line: string): PanguError | undefined {\n const named = ERROR_NAME.exec(line);\n const byThatName = named === null ? undefined : byName.get(named[1] ?? \"\");\n if (byThatName !== undefined) {\n return byThatName;\n }\n const numbered = ERROR_NUMBER.exec(line);\n const byThatNumber =\n numbered === null ? undefined : byCode.get(toCode(numbered[1] ?? \"\"));\n if (byThatNumber !== undefined) {\n return byThatNumber;\n }\n const custom = CUSTOM.exec(line);\n return custom === null ? undefined : byCode.get(toCode(custom[1] ?? \"\"));\n}\n\n/**\n * Finds Pangu's own refusal in a transaction's logs.\n *\n * Covers the two shapes a refusal arrives in: the Anchor line that names the\n * error, and the bare code the runtime prints when the program fails.\n *\n * A code only means something next to the program that raised it: DBC's 6002\n * is its slippage refusal, and Pangu's 6002 is WrongMint. So the lines are\n * walked as the runtime prints them, each \"invoke\" opening a frame and each\n * \"success\" or \"failed\" closing one, and the first \"failed\" names the program\n * the transaction really stopped in. The runtime aborts on the innermost\n * failure, so every later \"failed\" is only a caller passing it up. A refusal is\n * Pangu's only when that program is Pangu, and only lines printed inside\n * Pangu's own frame are read for its name. Pangu having run earlier in the same\n * transaction, which it does on every first buy when it opens the buyer\n * record, counts for nothing.\n *\n * A fragment that names no program at all is read as Pangu's, because there is\n * nobody else it could belong to.\n *\n * Does not cover: errors Pangu never raises, such as Anchor's own account checks\n * or the token program's, and logs cut short before the failing line when the\n * frame that failed is not Pangu's. Those come back as null and the caller should\n * show the raw message.\n */\nexport function panguErrorFromLogs(logs: string[]): PanguError | null {\n if (!Array.isArray(logs)) {\n return null;\n }\n\n const stack: string[] = [];\n let namedProgram = false;\n let failedProgram: string | null = null;\n let failedReason = \"\";\n // The last refusal printed inside a Pangu frame that has not succeeded.\n let panguSaid: PanguError | undefined;\n\n for (const entry of logs) {\n if (typeof entry !== \"string\") {\n continue;\n }\n const line = entry.trim();\n\n const invoke = INVOKE.exec(line);\n if (invoke !== null) {\n namedProgram = true;\n stack.push(invoke[1] ?? \"\");\n continue;\n }\n\n const succeeded = SUCCESS.exec(line);\n if (succeeded !== null) {\n namedProgram = true;\n stack.pop();\n // A Pangu frame that succeeded refused nothing, whatever it logged.\n if (succeeded[1] === PANGU) {\n panguSaid = undefined;\n }\n continue;\n }\n\n const failed = FAILED.exec(line);\n if (failed !== null) {\n namedProgram = true;\n if (failedProgram === null) {\n failedProgram = failed[1] ?? \"\";\n failedReason = failed[2] ?? \"\";\n }\n stack.pop();\n continue;\n }\n\n const current = stack[stack.length - 1];\n if (current === PANGU || !namedProgram) {\n panguSaid = refusalIn(line) ?? panguSaid;\n }\n }\n\n if (!namedProgram) {\n return panguSaid ?? null;\n }\n if (failedProgram === null) {\n // Cut short before any frame closed as failed. Only a refusal printed inside\n // Pangu's own frame, still open, can be trusted as Pangu's.\n return stack.includes(PANGU) ? panguSaid ?? null : null;\n }\n if (failedProgram !== PANGU) {\n return null;\n }\n const custom = CUSTOM.exec(failedReason);\n const byFailedCode =\n custom === null ? undefined : byCode.get(toCode(custom[1] ?? \"\"));\n return byFailedCode ?? panguSaid ?? null;\n}\n\n/**\n * One sentence a buyer can read for each refusal.\n *\n * Every name in the IDL has an entry. A name that is not Pangu's gets a sentence\n * that says so, rather than a guess.\n */\nconst EXPLANATIONS = {\n NotTransferring:\n \"This token only moves through a real transfer, and this was not one.\",\n ReceivingAccountOwnerCanChange:\n \"The account you are buying into could be handed to someone else later, so the sale will not send tokens to it. Use the wallet's ordinary holding account for this token, the one your wallet app makes by itself.\",\n WrongMint: \"That account belongs to a different token than this sale.\",\n WrongBuyerRecord:\n \"The buyer record sent with this transfer belongs to another wallet.\",\n BuyerRecordMissing:\n \"This wallet has no record in the sale yet. Open one first, then buy.\",\n NotApproved: \"The issuer has not approved this wallet to buy in this sale.\",\n CredentialInvalid:\n \"This wallet does not carry a valid approval from the verifier this sale trusts.\",\n CredentialExpired: \"The verifier's approval for this wallet has run out.\",\n CredentialSignerNotAuthorized:\n \"The key that signed this wallet's approval is no longer allowed to sign for that verifier.\",\n OverCap: \"This purchase would take your wallet past the limit for this sale.\",\n WalletToWalletDuringSale:\n \"This token cannot be sent from one wallet to another while the sale is running.\",\n PriceStale:\n \"The stock price this sale checks against is too old to use. Refresh it and try again. Outside market hours there is no fresh price to get, so the sale stays shut until the market opens.\",\n PriceOutsideBand:\n \"This purchase would push the price too far above the real stock price.\",\n WrongPriceAccount:\n \"The price account sent with this transfer is not the one this sale names.\",\n PriceNotFullyVerified:\n \"The price update has not been signed by two thirds of Pyth's guardians, and this sale will not price against a half signed number.\",\n PriceTooUncertain:\n \"Pyth's own publishers disagree about this stock's price by more than this sale allows, so there is no ceiling worth measuring against right now.\",\n NotPoolCreator: \"Only the wallet that created the pool can open its sale.\",\n NotAHookPool:\n \"That account is not a Meteora bonding curve pool of the kind Pangu works with.\",\n HookProgramMismatch:\n \"This token does not name Pangu as its transfer hook, so Pangu cannot hold its rules.\",\n MintAuthorityStillSet:\n \"This token can still be minted, so Pangu will not open a sale on it. Launch it with the minting power revoked.\",\n WrongLaunchTemplate:\n \"That launch template is not the one this pool was opened on.\",\n FeesNotInQuoteToken:\n \"This sale's template collects fees in the sale token, and Pangu only accepts templates that collect them in the paying token.\",\n ZeroCap: \"A sale needs a per-wallet limit above zero.\",\n InvalidAccessMode:\n \"That access mode does not exist, or the settings do not match the mode chosen.\",\n InvalidBand: \"The price band settings are incomplete or out of range.\",\n SaleStillRunning:\n \"The sale is still running and this record still counts tokens, so it cannot be closed yet. Sell them back or wait for the sale to finish.\",\n NotIssuer: \"Only the issuer of this sale can do that.\",\n MathOverflow: \"The sale's counters cannot go any higher.\",\n WrongLayoutVersion:\n \"These sale rules were written by an older build of the program, so this build will not act on them.\",\n BandNeedsDollarQuote:\n \"A price ceiling needs buyers to pay in a dollar token the program recognises (USDC, or on devnet the demo dollar). Turn the ceiling off, or pick a dollar paying token.\",\n IssuerControlsPayingToken:\n \"You hold the freeze authority of the token buyers pay in, which would let you stop sellers being paid. Pick a paying token whose freeze authority is not yours.\",\n CapCoversWholeSale:\n \"The per-wallet limit is as large as everything the curve sells, so one wallet could buy the whole sale. Set a limit below the curve's supply.\",\n EndInThePast:\n \"The end of the offering period has to be later than now. Pick a future time, or leave it at zero for no end.\",\n} as const;\n\nexport type PanguErrorName = keyof typeof EXPLANATIONS;\n\nexport function explainPanguError(name: PanguErrorName | string): string {\n const explanation = (EXPLANATIONS as Record<string, string | undefined>)[name];\n return (\n explanation ??\n \"The transaction was refused, and the reason did not come from this sale's rules.\"\n );\n}\n","import {\n SYSVAR_CLOCK_PUBKEY,\n PublicKey as Web3PublicKey,\n type Connection,\n type PublicKey,\n} from \"@solana/web3.js\";\nimport type { Sale } from \"./accounts.js\";\nimport { priceFeedAddress } from \"./addresses.js\";\nimport { confidenceBps, dollars, stockPriceDollars } from \"./band.js\";\nimport { LIMITS, PYTH_RECEIVER_PROGRAM_ID } from \"./constants.js\";\nimport type { PanguErrorName } from \"./errors.js\";\nimport { explainPanguError } from \"./errors.js\";\nimport { PanguInputError } from \"./inputs.js\";\n\n/** What one Pyth price feed account carries. */\nexport interface PriceUpdate {\n /** The key Pyth's receiver program recorded as having written this update. */\n writeAuthority: PublicKey;\n /** True when two thirds of the Wormhole guardians signed it. */\n fullyVerified: boolean;\n /** Lowercase hex, no prefix, matching Sale.priceFeedId. */\n feedId: string;\n /** Pyth's whole number. The dollar price is this times ten to the exponent. */\n price: bigint;\n /** How wide the publishers' disagreement is, in the same units as the price. */\n conf: bigint;\n exponent: number;\n /** Unix seconds Pyth's publishers agreed this price. */\n publishTime: number;\n prevPublishTime: number;\n /** The Solana slot the update was posted in. */\n postedSlot: bigint;\n}\n\n/** A sale's live stock price, and whether a buy could use it right now. */\nexport interface PriceReading {\n /** The Pyth price feed account this sale reads. */\n address: PublicKey;\n /** The stock price in dollars, scaled by 1e18. Zero when there is none. */\n price: bigint;\n /** The same price as an ordinary number, for display. */\n priceDollars: number;\n /** Unix seconds the price was published, or zero when unknown. */\n publishTime: number;\n /** How old it is, in seconds, against the chain's own clock. */\n ageSecs: number;\n /** Pyth's confidence interval as basis points of the price, rounded up. */\n confBps: number;\n /** True when two thirds of the Wormhole guardians signed the update. */\n fullyVerified: boolean;\n usable: boolean;\n /** Why it cannot be used, as the program's own refusal. Null when usable. */\n error: PanguErrorName | null;\n /** One sentence for a buyer. Null when usable. */\n reason: string | null;\n}\n\n/**\n * The first eight bytes of sha256(\"account:PriceUpdateV2\"), the discriminator\n * Anchor writes in front of every price feed account. Read off Pyth's own\n * mainnet AAPL account, see docs/measurements/price-band-pyth.md.\n */\nconst DISCRIMINATOR = [34, 241, 35, 99, 157, 126, 244, 205];\n\n/**\n * Borsh writes `VerificationLevel::Partial { num_signatures }` first and `Full`\n * second, so Partial is tag 0 followed by one more byte and Full is tag 1 with\n * nothing after it. Every offset after the tag moves by one on a Partial\n * update, which is why the tag is read before any field is.\n */\nconst PARTIAL_TAG = 0;\nconst FULL_TAG = 1;\n\nconst WRITE_AUTHORITY_OFFSET = 8;\nconst VERIFICATION_OFFSET = 40;\n\n/** price.rs PUBLISH_FUTURE_TOLERANCE_SECS: Pyth's clock is not Solana's. */\nconst PUBLISH_FUTURE_TOLERANCE_SECS = 60;\n\n/** Where the Clock sysvar keeps its Unix time: slot, epoch start, epoch, schedule. */\nconst CLOCK_UNIX_TIMESTAMP_OFFSET = 32;\n\nfunction slice(data: Uint8Array, start: number, length: number): Uint8Array {\n const end = start + length;\n if (start < 0 || length < 0 || end > data.length) {\n throw new PanguInputError(\n \"these bytes are not a Pyth price update: they end before the layout does\"\n );\n }\n return data.subarray(start, end);\n}\n\nfunction hex(data: Uint8Array): string {\n return Array.from(data, (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nfunction unsigned(data: Uint8Array, offset: number, length: number): bigint {\n const bytes = slice(data, offset, length);\n let value = 0n;\n for (let index = length - 1; index >= 0; index -= 1) {\n value = (value << 8n) | BigInt(bytes[index] ?? 0);\n }\n return value;\n}\n\nfunction signed(data: Uint8Array, offset: number, length: number): bigint {\n const value = unsigned(data, offset, length);\n const bits = BigInt(length * 8);\n return value >= 1n << (bits - 1n) ? value - (1n << bits) : value;\n}\n\n/**\n * Reads a Pyth price feed account without the Pyth package.\n *\n * Every offset is the one `programs/pangu/src/price.rs` reads on chain through\n * Pyth's own Rust SDK, checked against the real account bytes in\n * docs/measurements/price-band-pyth.md. Safe in a browser: it is arithmetic\n * over bytes the caller already has, and it pulls in nothing.\n *\n * A partly verified update is decoded rather than refused, because the caller\n * has to be able to say which of the two it is. `fullyVerified` is the answer,\n * and `readPrice` refuses on it.\n *\n * Throws PanguInputError for anything that is not a well formed price update.\n */\nexport function decodePriceUpdate(data: Uint8Array): PriceUpdate {\n const discriminator = slice(data, 0, DISCRIMINATOR.length);\n if (DISCRIMINATOR.some((byte, index) => discriminator[index] !== byte)) {\n throw new PanguInputError(\"these bytes are not a Pyth price feed account\");\n }\n\n const tag = slice(data, VERIFICATION_OFFSET, 1)[0];\n if (tag !== FULL_TAG && tag !== PARTIAL_TAG) {\n throw new PanguInputError(\n `${String(tag)} is not a verification level Pyth writes, so these bytes cannot be read`\n );\n }\n const message = VERIFICATION_OFFSET + (tag === FULL_TAG ? 1 : 2);\n\n return {\n writeAuthority: new Web3PublicKey(slice(data, WRITE_AUTHORITY_OFFSET, 32)),\n fullyVerified: tag === FULL_TAG,\n feedId: hex(slice(data, message, 32)),\n price: signed(data, message + 32, 8),\n conf: unsigned(data, message + 40, 8),\n exponent: Number(signed(data, message + 48, 4)),\n publishTime: Number(signed(data, message + 52, 8)),\n prevPublishTime: Number(signed(data, message + 60, 8)),\n postedSlot: unsigned(data, message + 84, 8),\n };\n}\n\nfunction unusable(\n address: PublicKey,\n error: PanguErrorName,\n partial: Partial<PriceReading> = {}\n): PriceReading {\n return {\n address,\n price: 0n,\n priceDollars: 0,\n publishTime: 0,\n ageSecs: 0,\n confBps: 0,\n fullyVerified: false,\n usable: false,\n error,\n reason: explainPanguError(error),\n ...partial,\n };\n}\n\n/**\n * The live stock price a banded sale checks against, read straight off the\n * chain, plus whether a buy could use it this moment.\n *\n * Runs the hook's own checks in the hook's own order: the account sits at the\n * one address this sale's shard and feed id produce, it is owned by Pyth's\n * receiver program, its bytes are a price update, two thirds of the guardians\n * signed it, the feed inside it is this sale's feed, it is no older than the\n * sale allows, it was not published in the future, the price is above zero, and\n * Pyth's confidence interval is inside the sale's limit. Any doubt comes back\n * as `usable: false` with the program's own error name, because that is what\n * the buy would hit.\n *\n * The age is measured against the chain's own clock, the same clock the hook\n * compares against, rather than this machine's. If the Clock sysvar cannot be\n * read, this machine's clock stands in.\n *\n * Does not cover the Wormhole guardian signatures. Nothing can redo those from\n * the account's bytes: what stands in for them is the owner check, because only\n * Pyth's receiver program can write an account it owns and it checks them\n * first.\n *\n * Throws PanguInputError when the sale has no price band.\n */\nexport async function readPrice(\n connection: Connection,\n sale: Sale\n): Promise<PriceReading> {\n if (sale === null || sale === undefined || !sale.hasBand) {\n throw new PanguInputError(\n \"this sale has no price band, so there is no price account to read\"\n );\n }\n const address = sale.priceAccount;\n\n // The rules carry both the address and the two values it is derived from. If\n // they ever disagree, the bytes at that address are not this sale's price.\n if (!priceFeedAddress(sale.priceFeedId, sale.priceShard).equals(address)) {\n return unusable(address, \"WrongPriceAccount\");\n }\n\n const [info, clock] = await connection.getMultipleAccountsInfo([\n address,\n SYSVAR_CLOCK_PUBKEY,\n ]);\n if (info === null || info === undefined) {\n return unusable(address, \"PriceStale\");\n }\n if (!info.owner.equals(PYTH_RECEIVER_PROGRAM_ID)) {\n return unusable(address, \"WrongPriceAccount\");\n }\n\n let update: PriceUpdate;\n try {\n update = decodePriceUpdate(info.data);\n } catch {\n return unusable(address, \"WrongPriceAccount\");\n }\n\n if (!update.fullyVerified) {\n return unusable(address, \"PriceNotFullyVerified\", {\n publishTime: update.publishTime,\n });\n }\n if (update.feedId !== sale.priceFeedId) {\n return unusable(address, \"WrongPriceAccount\");\n }\n if (\n update.price <= 0n ||\n update.exponent > 0 ||\n update.exponent < -LIMITS.maxDecimals\n ) {\n return unusable(\n address,\n update.price <= 0n ? \"PriceStale\" : \"WrongPriceAccount\",\n { fullyVerified: true, publishTime: update.publishTime }\n );\n }\n\n const now =\n clock !== null &&\n clock !== undefined &&\n clock.data.length >= CLOCK_UNIX_TIMESTAMP_OFFSET + 8\n ? Number(clock.data.readBigInt64LE(CLOCK_UNIX_TIMESTAMP_OFFSET))\n : Math.floor(Date.now() / 1000);\n\n const price = stockPriceDollars(update.price, update.exponent);\n const confBps = Number(confidenceBps(update.price, update.conf));\n const reading: PriceReading = {\n address,\n price,\n priceDollars: dollars(price),\n publishTime: update.publishTime,\n ageSecs: now - update.publishTime,\n confBps,\n fullyVerified: true,\n usable: true,\n error: null,\n reason: null,\n };\n\n const refuse = (error: PanguErrorName): PriceReading => ({\n ...reading,\n usable: false,\n error,\n reason: explainPanguError(error),\n });\n\n // A price may be old, within the sale's limit, but never newer than now. Pyth\n // stops publishing an equity outside its trading sessions, so a shut market\n // reaches this the same way a broken publisher does: the account stops moving\n // and ages out. There is no session flag to tell the two apart.\n if (\n reading.ageSecs > sale.maxPriceAgeSecs ||\n update.publishTime > now + PUBLISH_FUTURE_TOLERANCE_SECS ||\n price <= 0n\n ) {\n return refuse(\"PriceStale\");\n }\n if (confBps > sale.maxConfBps) {\n return refuse(\"PriceTooUncertain\");\n }\n\n return reading;\n}\n","import { PublicKey } from \"@solana/web3.js\";\nimport { SAS_PROGRAM_ID } from \"../constants.js\";\nimport type { PanguErrorName } from \"../errors.js\";\n\n/** An account as the RPC hands it back: who owns it and what is in it. */\nexport interface AccountBytes {\n owner: PublicKey;\n data: Uint8Array;\n}\n\n/** The two accounts the hook reads in mode 2, plus the clock it compares against. */\nexport interface CredentialState {\n /** The account at the one attestation address this wallet can have, or null. */\n attestation: AccountBytes | null;\n /** The credential the sale's rules name, or null when nothing is there. */\n credential: AccountBytes | null;\n /** Unix seconds, read off the chain's own clock rather than this machine's. */\n now: number;\n}\n\n/**\n * The layout the attestation service writes, mirrored from\n * programs/pangu/src/sas.rs. The blob between the stated length and the signer\n * is schema-shaped and means nothing here, so it is stepped over, not read.\n */\nconst ATTESTATION_DISCRIMINATOR = 2;\nconst CREDENTIAL_DISCRIMINATOR = 0;\nconst NONCE_OFFSET = 1;\nconst ATTESTATION_CREDENTIAL_OFFSET = 33;\nconst ATTESTATION_SCHEMA_OFFSET = 65;\nconst ATTESTATION_DATA_LEN_OFFSET = 97;\nconst ATTESTATION_DATA_OFFSET = 101;\nconst CREDENTIAL_NAME_LEN_OFFSET = 33;\nconst CREDENTIAL_NAME_OFFSET = 37;\nconst PUBKEY_LEN = 32;\n\n/** sas.rs MAX_AUTHORIZED_SIGNERS: a longer list is refused rather than walked. */\nconst MAX_AUTHORIZED_SIGNERS = 64;\n\n/** Zero expiry means the attestation never runs out. sas.rs NEVER_EXPIRES. */\nconst NEVER_EXPIRES = 0;\n\nfunction readPubkey(data: Uint8Array, offset: number): PublicKey | null {\n const end = offset + PUBKEY_LEN;\n if (!Number.isSafeInteger(end) || offset < 0 || end > data.length) {\n return null;\n }\n return new PublicKey(data.subarray(offset, end));\n}\n\nfunction readU32(data: Uint8Array, offset: number): number | null {\n const end = offset + 4;\n if (!Number.isSafeInteger(end) || offset < 0 || end > data.length) {\n return null;\n }\n return new DataView(data.buffer, data.byteOffset + offset, 4).getUint32(0, true);\n}\n\nfunction readI64(data: Uint8Array, offset: number): bigint | null {\n const end = offset + 8;\n if (!Number.isSafeInteger(end) || offset < 0 || end > data.length) {\n return null;\n }\n return new DataView(data.buffer, data.byteOffset + offset, 8).getBigInt64(0, true);\n}\n\ninterface Attestation {\n nonce: PublicKey;\n credential: PublicKey;\n schema: PublicKey;\n signer: PublicKey;\n expiry: bigint;\n}\n\nfunction parseAttestation(account: AccountBytes): Attestation | null {\n if (!account.owner.equals(SAS_PROGRAM_ID)) {\n return null;\n }\n const data = account.data;\n if (data.length === 0 || data[0] !== ATTESTATION_DISCRIMINATOR) {\n return null;\n }\n const nonce = readPubkey(data, NONCE_OFFSET);\n const credential = readPubkey(data, ATTESTATION_CREDENTIAL_OFFSET);\n const schema = readPubkey(data, ATTESTATION_SCHEMA_OFFSET);\n const blobLength = readU32(data, ATTESTATION_DATA_LEN_OFFSET);\n if (nonce === null || credential === null || schema === null || blobLength === null) {\n return null;\n }\n const signerOffset = ATTESTATION_DATA_OFFSET + blobLength;\n const signer = readPubkey(data, signerOffset);\n const expiry = readI64(data, signerOffset + PUBKEY_LEN);\n if (signer === null || expiry === null) {\n return null;\n }\n return { nonce, credential, schema, signer, expiry };\n}\n\n/**\n * Whether the credential lists this key as an authorized signer right now.\n *\n * Null when the account is not a credential at all, or claims a list longer\n * than the hook will walk, so the caller can tell \"no\" from \"unreadable\".\n */\nfunction listsSigner(account: AccountBytes, signer: PublicKey): boolean | null {\n if (!account.owner.equals(SAS_PROGRAM_ID)) {\n return null;\n }\n const data = account.data;\n if (data.length === 0 || data[0] !== CREDENTIAL_DISCRIMINATOR) {\n return null;\n }\n const nameLength = readU32(data, CREDENTIAL_NAME_LEN_OFFSET);\n if (nameLength === null) {\n return null;\n }\n const countOffset = CREDENTIAL_NAME_OFFSET + nameLength;\n const count = readU32(data, countOffset);\n if (count === null || count > MAX_AUTHORIZED_SIGNERS) {\n return null;\n }\n let offset = countOffset + 4;\n for (let index = 0; index < count; index += 1) {\n const key = readPubkey(data, offset);\n if (key === null) {\n return null;\n }\n if (key.equals(signer)) {\n return true;\n }\n offset += PUBKEY_LEN;\n }\n return false;\n}\n\n/**\n * The refusal the transfer hook would give this wallet in access mode 2, or null\n * when the hook would let the buy through.\n *\n * Reads the same bytes in the same order as `require_attestation` in\n * programs/pangu/src/instructions/execute.rs: the credential has to be the\n * service's own account of the right kind, the attestation has to sit at the one\n * address this sale's credential, schema and wallet derive, it has to agree with\n * its own address, it has to be in date, and the key that signed it has to still\n * be on the credential's list. Anything missing, foreign, truncated or\n * self-contradicting is CredentialInvalid, the same way the hook fails closed.\n *\n * What it cannot see: the moment the buy actually lands. A revocation between\n * this read and the transaction changes the answer, and the chain has the last\n * word.\n */\nexport function credentialRefusal(\n rules: { credential: PublicKey; schema: PublicKey },\n wallet: PublicKey,\n state: CredentialState\n): PanguErrorName | null {\n if (state.attestation === null || state.credential === null) {\n return \"CredentialInvalid\";\n }\n\n const attested = parseAttestation(state.attestation);\n if (attested === null) {\n return \"CredentialInvalid\";\n }\n if (\n !attested.credential.equals(rules.credential) ||\n !attested.schema.equals(rules.schema) ||\n !attested.nonce.equals(wallet)\n ) {\n return \"CredentialInvalid\";\n }\n\n const expiry = attested.expiry;\n if (expiry !== BigInt(NEVER_EXPIRES) && expiry <= BigInt(Math.floor(state.now))) {\n return \"CredentialExpired\";\n }\n\n const authorized = listsSigner(state.credential, attested.signer);\n if (authorized === null) {\n return \"CredentialInvalid\";\n }\n return authorized ? null : \"CredentialSignerNotAuthorized\";\n}\n","import type { Connection, PublicKey, Transaction, TransactionInstruction } from \"@solana/web3.js\";\nimport { BN } from \"@anchor-lang/core\";\nimport {\n createAssociatedTokenAccountIdempotentInstruction,\n getAssociatedTokenAddressSync,\n} from \"@solana/spl-token\";\nimport { TOKEN_2022_PROGRAM_ID } from \"../constants.js\";\nimport { PanguInputError } from \"../inputs.js\";\nimport { COMPUTE_LIMIT, computeLimit, requireOneTransaction } from \"./budget.js\";\nimport { hookAccounts, hookAccountsInfo, type PendingTokenAccount } from \"./hook.js\";\nimport { DBC_POOL_AUTHORITY, dbcProgram, loadPool, readyToSign } from \"./state.js\";\n\n/** Everything a claim leaves the caller with. */\nexport interface ClaimFees {\n transaction: Transaction;\n /** Who the fees go to, read from the pool and its template, not passed in. */\n claimer: PublicKey;\n bytes: number;\n computeUnitLimit: number;\n}\n\nexport interface ClaimFeesInput {\n connection: Connection;\n who: \"partner\" | \"creator\";\n mint: PublicKey;\n}\n\n/** u64 max: claim everything that has built up. */\nconst EVERYTHING = new BN(\"18446744073709551615\");\n\n/**\n * Claims the trading fees of a sale that is still running.\n *\n * Meteora's own `claimPartnerTradingFee` calls the older instruction, which\n * refuses a transfer hook pool with `PoolTypeMismatch`. This builds the hook\n * aware pair, `claim_trading_fee2` and `claim_creator_trading_fee2`, with the\n * hook's accounts attached. See finding 2 in docs/measurements/fork-test.md.\n *\n * The claimer is read off the chain: the partner is the template's fee claimer\n * and the creator is the pool's creator, so no address a caller typed in can\n * receive this money. The sale's fees are collected in the paying token only\n * (C11), so no sale token moves here.\n *\n * Throws PanguInputError for a mint with no Pangu sale.\n */\nexport async function claimFeesTransaction(\n input: ClaimFeesInput\n): Promise<ClaimFees> {\n if (input.who !== \"partner\" && input.who !== \"creator\") {\n throw new PanguInputError('who must be \"partner\" or \"creator\"');\n }\n const view = await loadPool(input.connection, input.mint);\n const claimer =\n input.who === \"partner\"\n ? view.configState.feeClaimer\n : view.poolAccount.poolState.creator;\n\n const baseAta = getAssociatedTokenAddressSync(\n view.baseMint,\n claimer,\n false,\n TOKEN_2022_PROGRAM_ID\n );\n const quoteAta = getAssociatedTokenAddressSync(\n view.quoteMint,\n claimer,\n false,\n view.quoteProgram\n );\n\n const pending: PendingTokenAccount[] = [];\n const pre: TransactionInstruction[] = [computeLimit(COMPUTE_LIMIT.claim)];\n if ((await input.connection.getAccountInfo(baseAta)) === null) {\n pending.push({ address: baseAta, mint: view.baseMint, owner: claimer });\n }\n pre.push(\n createAssociatedTokenAccountIdempotentInstruction(\n claimer,\n baseAta,\n claimer,\n view.baseMint,\n TOKEN_2022_PROGRAM_ID\n ),\n createAssociatedTokenAccountIdempotentInstruction(\n claimer,\n quoteAta,\n claimer,\n view.quoteMint,\n view.quoteProgram\n )\n );\n\n // The claim moves the paying token, but DBC still hands the hook's accounts\n // to the token program for the base side, so they are resolved for the pair\n // this claim would move: out of the pool's vault, into the claimer's account.\n const hook = await hookAccounts({\n connection: input.connection,\n mint: view.baseMint,\n source: view.baseVault,\n destination: baseAta,\n authority: DBC_POOL_AUTHORITY,\n amount: 0n,\n pending,\n });\n\n const shared = {\n poolAuthority: DBC_POOL_AUTHORITY,\n pool: view.pool,\n tokenAAccount: baseAta,\n tokenBAccount: quoteAta,\n baseVault: view.baseVault,\n quoteVault: view.quoteVault,\n baseMint: view.baseMint,\n quoteMint: view.quoteMint,\n tokenBaseProgram: TOKEN_2022_PROGRAM_ID,\n tokenQuoteProgram: view.quoteProgram,\n };\n\n const program = dbcProgram(input.connection);\n const builder =\n input.who === \"partner\"\n ? program.methods\n .claimTradingFee2(new BN(0), EVERYTHING, hookAccountsInfo(hook))\n .accountsPartial({ ...shared, config: view.config, feeClaimer: claimer })\n : program.methods\n .claimCreatorTradingFee2(new BN(0), EVERYTHING, hookAccountsInfo(hook))\n .accountsPartial({ ...shared, creator: claimer });\n\n const transaction = await builder\n .remainingAccounts(hook)\n .preInstructions(pre)\n .transaction();\n\n await readyToSign(input.connection, transaction, claimer);\n return {\n transaction,\n claimer,\n bytes: requireOneTransaction(transaction, `the ${input.who} fee claim`),\n computeUnitLimit: COMPUTE_LIMIT.claim,\n };\n}\n","import type { Connection, Keypair, PublicKey, Transaction } from \"@solana/web3.js\";\nimport {\n DAMM_V2_MIGRATION_FEE_ADDRESS,\n DynamicBondingCurveClient,\n deriveDammV2PoolAddress,\n} from \"@meteora-ag/dynamic-bonding-curve-sdk\";\nimport { PanguInputError, requireRealPublicKey } from \"../inputs.js\";\nimport { requireOneTransaction } from \"./budget.js\";\nimport { loadPool, readyToSign, type PoolView } from \"./state.js\";\n\n/** How far a sale has got, in the numbers a judge or a buyer reads. */\nexport interface SaleProgress {\n /** Raw units of the paying token the curve has taken in. */\n quoteRaised: bigint;\n /** What it has to reach before the sale graduates. */\n threshold: bigint;\n /** Between 0 and 1. */\n percent: number;\n /** True once the curve is full, whether or not anybody has migrated it yet. */\n graduated: boolean;\n /** The DAMM v2 pool, once migration has created it. */\n dammPool: PublicKey | null;\n}\n\nexport interface GraduateInput {\n connection: Connection;\n /** Anyone may pay for this. It is permissionless. */\n payer: PublicKey;\n mint: PublicKey;\n}\n\nexport interface Graduate {\n transaction: Transaction;\n /** The two position accounts migration creates. Both sign this transaction. */\n signers: Keypair[];\n /** Where the liquidity lands. */\n dammPool: PublicKey;\n bytes: number;\n}\n\nfunction dammConfigOf(view: PoolView): PublicKey {\n const option = view.configState.migrationFeeOption;\n const config = DAMM_V2_MIGRATION_FEE_ADDRESS[option];\n if (config === undefined) {\n throw new PanguInputError(\n `this template names migration fee option ${option}, which DAMM v2 has no config for`\n );\n }\n return config;\n}\n\n/**\n * Migrates a full curve into DAMM v2.\n *\n * Permissionless: anyone can send it, and the sale's own creator gets the\n * locked liquidity whoever pays. No compute budget instruction is added, on\n * purpose: migration measured 153,633 units against the 200,000 a single\n * instruction gets by default, and the transaction is already 1,139 bytes.\n *\n * Throws PanguInputError when the curve is not full yet or has already been\n * migrated.\n */\nexport async function graduateTransaction(\n input: GraduateInput\n): Promise<Graduate> {\n const payer = requireRealPublicKey(input.payer, \"payer\");\n const view = await loadPool(input.connection, input.mint);\n const state = view.poolAccount.poolState;\n\n if (state.isMigrated !== 0) {\n throw new PanguInputError(\"this sale has already been migrated to DAMM v2\");\n }\n if (state.quoteReserve.lt(view.configState.migrationQuoteThreshold)) {\n throw new PanguInputError(\n \"the curve is not full yet, so there is nothing to migrate\"\n );\n }\n\n const dammConfig = dammConfigOf(view);\n const client = new DynamicBondingCurveClient(input.connection, \"confirmed\");\n const { transaction, firstPositionNftKeypair, secondPositionNftKeypair } =\n await client.migration.migrateToDammV2({\n pool: view.pool,\n dammConfig,\n payer,\n });\n\n await readyToSign(input.connection, transaction, payer);\n return {\n transaction,\n signers: [firstPositionNftKeypair, secondPositionNftKeypair],\n dammPool: deriveDammV2PoolAddress(dammConfig, view.baseMint, view.quoteMint),\n bytes: requireOneTransaction(transaction, \"the migration to DAMM v2\"),\n };\n}\n\n/**\n * How far this sale has got, read from the pool and its template.\n *\n * `graduated` is the curve being full, which is the moment DBC takes the hook\n * off the mint. `dammPool` stays null until somebody sends the migration, so\n * the two questions the app asks, \"is the sale over\" and \"where does it trade\n * now\", are answered separately.\n *\n * Throws PanguInputError for a mint with no Pangu sale.\n */\nexport async function saleProgress(\n connection: Connection,\n mint: PublicKey\n): Promise<SaleProgress> {\n const view = await loadPool(connection, mint);\n const quoteRaised = BigInt(view.poolAccount.poolState.quoteReserve.toString());\n const threshold = BigInt(view.configState.migrationQuoteThreshold.toString());\n const dammPool = deriveDammV2PoolAddress(\n dammConfigOf(view),\n view.baseMint,\n view.quoteMint\n );\n const exists = await connection.getAccountInfo(dammPool);\n\n return {\n quoteRaised,\n threshold,\n percent:\n threshold === 0n\n ? 0\n : Math.min(1, Number((quoteRaised * 1_000_000n) / threshold) / 1_000_000),\n graduated: quoteRaised >= threshold,\n dammPool: exists === null ? null : dammPool,\n };\n}\n"],"mappings":"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","names":["import_web3","import_dynamic_bonding_curve_sdk","import_web3","import_web3","import_spl_token","import_web3","import_web3","import_dynamic_bonding_curve_sdk","import_core","import_web3","import_web3","import_core","import_spl_token","import_dynamic_bonding_curve_sdk","import_core","import_dynamic_bonding_curve_sdk","import_buffer","import_spl_token","import_dynamic_bonding_curve_sdk","meta","import_web3","import_web3","Web3PublicKey","import_web3","CLOCK_UNIX_TIMESTAMP_OFFSET","import_core","import_spl_token","import_dynamic_bonding_curve_sdk"]}