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.
- package/LICENSE +21 -0
- package/README.md +217 -0
- package/dist/accounts-BuD-oCcr.d.mts +206 -0
- package/dist/accounts-BuD-oCcr.d.ts +206 -0
- package/dist/dbc.d.mts +505 -0
- package/dist/dbc.d.ts +505 -0
- package/dist/dbc.js +3003 -0
- package/dist/dbc.js.map +1 -0
- package/dist/dbc.mjs +3027 -0
- package/dist/dbc.mjs.map +1 -0
- package/dist/feed-CY-pcUU2.d.mts +269 -0
- package/dist/feed-Zwu1irEx.d.ts +269 -0
- package/dist/index.d.mts +415 -0
- package/dist/index.d.ts +415 -0
- package/dist/index.js +2809 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2803 -0
- package/dist/index.mjs.map +1 -0
- package/dist/price.d.mts +86 -0
- package/dist/price.d.ts +86 -0
- package/dist/price.js +1554 -0
- package/dist/price.js.map +1 -0
- package/dist/price.mjs +1533 -0
- package/dist/price.mjs.map +1 -0
- package/package.json +104 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/idl/pangu.json","../src/inputs.ts","../src/addresses.ts","../src/accounts.ts","../src/coder.ts","../src/band.ts","../src/feed.ts","../src/errors.ts","../src/standing.ts","../src/directory.ts","../src/instructions.ts","../src/sas.ts"],"sourcesContent":["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 { 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 { 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 { 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 { 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 {\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 { 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 type { PublicKey } from \"@solana/web3.js\";\nimport type { BuyerRecord, Sale } from \"./accounts.js\";\nimport { PanguInputError } from \"./inputs.js\";\n\n/** How concentrated a sale is right now, from the records themselves. */\nexport interface SaleStanding {\n /** Wallets holding more than zero net of what they sold back. */\n buyers: number;\n /** Everything the pool has sold, net of sells, in raw token units. */\n totalNetBought: bigint;\n /** The wallet holding the most, or null when nothing has been sold. */\n largestWallet: PublicKey | null;\n largestNetBought: bigint;\n /** The largest wallet's share of everything sold, 0 to 1. */\n largestShare: number;\n /** What one wallet's cap is worth as a share of everything sold, 0 to 1 and above. */\n capShare: number;\n /**\n * True once the sale's offering period has ended: from then on the hook\n * counts nothing and the token moves freely. Always false for a sale with no\n * end, which includes every version 1 sale.\n */\n offeringOver: boolean;\n}\n\n/** Nine decimal places is far past what any share bar in the app can show. */\nconst SHARE_SCALE = 1_000_000_000n;\n\nfunction share(part: bigint, whole: bigint): number {\n if (whole <= 0n) {\n return 0;\n }\n return Number((part * SHARE_SCALE) / whole) / Number(SHARE_SCALE);\n}\n\n/**\n * Works out how concentrated a sale is from its records.\n *\n * The counts come from the records, not from the rules account's own running\n * totals, so what the app shows is the sum of the accounts a judge can open.\n * Records belonging to another sale are refused rather than ignored: silently\n * dropping them would understate the largest holder.\n *\n * `now` is the Unix second to judge the offering period against. Pass the\n * chain's clock when you have it, because that is the clock the hook reads and\n * a browser's can be minutes out; without it this machine's clock stands in,\n * which can only misjudge the end within that drift.\n */\nexport function saleStanding(\n sale: Sale,\n records: BuyerRecord[],\n now: number = Math.floor(Date.now() / 1000)\n): SaleStanding {\n if (!Array.isArray(records)) {\n throw new PanguInputError(\"records must be an array of buyer records\");\n }\n\n let total = 0n;\n let buyers = 0;\n let largestWallet: PublicKey | null = null;\n let largestNetBought = 0n;\n\n for (const record of records) {\n if (!record.mint.equals(sale.mint)) {\n throw new PanguInputError(\n `a record for ${record.mint.toBase58()} was passed with the sale of ${sale.mint.toBase58()}`\n );\n }\n total += record.netBought;\n if (record.netBought > 0n) {\n buyers += 1;\n }\n if (record.netBought > largestNetBought) {\n largestNetBought = record.netBought;\n largestWallet = record.wallet;\n }\n }\n\n return {\n buyers,\n totalNetBought: total,\n largestWallet,\n largestNetBought,\n largestShare: share(largestNetBought, total),\n capShare: share(sale.cap, total),\n offeringOver: sale.endsAt !== null && now >= sale.endsAt,\n };\n}\n","import { SYSVAR_CLOCK_PUBKEY } from \"@solana/web3.js\";\nimport type { AccountInfo, Connection, PublicKey } from \"@solana/web3.js\";\nimport {\n ExtensionType,\n getExtensionData,\n getMetadataPointerState,\n unpackMint,\n type Mint,\n} from \"@solana/spl-token\";\nimport { listSales, mintRunsPangu, type ListSalesOptions, type Sale } from \"./accounts.js\";\nimport { DBC_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from \"./constants.js\";\nimport { requirePublicKey } from \"./inputs.js\";\nimport { saleStanding } from \"./standing.js\";\n\n/** A sale token's name, symbol and metadata link, as the mint itself carries them. */\nexport interface SaleTokenInfo {\n name: string;\n symbol: string;\n uri: string;\n}\n\n/** The update authority and the mint, each 32 bytes, come before the name. */\nconst METADATA_NAME_OFFSET = 64;\n\nfunction readMint(mint: PublicKey, info: AccountInfo<Uint8Array> | null): Mint | null {\n if (info === null || !info.owner.equals(TOKEN_2022_PROGRAM_ID)) {\n return null;\n }\n try {\n return unpackMint(mint, info as AccountInfo<Buffer>, TOKEN_2022_PROGRAM_ID);\n } catch {\n return null;\n }\n}\n\n/**\n * The name, symbol and link out of a Token-2022 metadata extension, or null\n * when the bytes do not hold exactly what the layout says they hold.\n *\n * The extension is three length-prefixed strings after two keys, followed by\n * extra fields this reader has no use for. Every length is checked against what\n * is left before it is read, and the text must be valid UTF-8.\n */\nfunction decodeMetadata(mint: PublicKey, data: Uint8Array): SaleTokenInfo | null {\n if (data.length < METADATA_NAME_OFFSET) {\n return null;\n }\n const named = data.subarray(32, METADATA_NAME_OFFSET);\n if (!mint.toBytes().every((byte, index) => byte === named[index])) {\n return null;\n }\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const utf8 = new TextDecoder(\"utf-8\", { fatal: true });\n const fields: string[] = [];\n let offset = METADATA_NAME_OFFSET;\n for (let field = 0; field < 3; field += 1) {\n if (offset + 4 > data.length) {\n return null;\n }\n const length = view.getUint32(offset, true);\n offset += 4;\n if (length > data.length - offset) {\n return null;\n }\n try {\n fields.push(utf8.decode(data.subarray(offset, offset + length)));\n } catch {\n return null;\n }\n offset += length;\n }\n const [name, symbol, uri] = fields as [string, string, string];\n return { name, symbol, uri };\n}\n\n/** The token info out of mint bytes already in hand. */\nfunction tokenInfoFromMint(\n mint: PublicKey,\n info: AccountInfo<Uint8Array> | null\n): SaleTokenInfo | null {\n const state = readMint(mint, info);\n if (state === null) {\n return null;\n }\n const pointer = getMetadataPointerState(state);\n if (pointer?.metadataAddress?.equals(mint) !== true) {\n return null;\n }\n const data = getExtensionData(ExtensionType.TokenMetadata, state.tlvData);\n return data === null ? null : decodeMetadata(mint, data);\n}\n\n/**\n * The sale token's name, symbol and metadata link.\n *\n * DBC writes these into the Token-2022 metadata extension on the mint itself,\n * with the mint's metadata pointer naming the mint, when the pool opens. Only\n * that shape is read: a pointer naming some other account means the copy on the\n * mint is not the one the token claims, so the answer is null rather than a\n * guess. Null too when the mint does not exist, is not a Token-2022 mint, or\n * carries no metadata.\n *\n * The text is whatever the issuer typed at launch and nothing checks it, so\n * show it as a label, never trust it as an identity: two sales can carry the\n * same name. The mint address is what identifies a sale.\n */\nexport async function saleTokenInfo(\n connection: Connection,\n mint: PublicKey\n): Promise<SaleTokenInfo | null> {\n const key = requirePublicKey(mint, \"mint\");\n return tokenInfoFromMint(key, await connection.getAccountInfo(key));\n}\n\n/** One sale as a list page shows it. */\nexport interface SaleDirectoryEntry {\n mint: PublicKey;\n pool: PublicKey;\n /** From the mint's metadata. Null when the mint carries none this package reads. */\n name: string | null;\n symbol: string | null;\n /** True while the mint still names Pangu as its transfer hook, as `isSaleRunning`. */\n running: boolean;\n /**\n * True once the curve is full, read from DBC's own record on the pool. Null\n * when the pool the rules name cannot be read as the transfer hook pool\n * selling this mint.\n */\n graduated: boolean | null;\n /** True once the offering period has ended by the chain's clock. */\n offeringOver: boolean;\n hasBand: boolean;\n accessMode: number;\n quoteMint: PublicKey | null;\n endsAt: number | null;\n buyers: number;\n issuer: PublicKey;\n /** The full rules, with the token's decimals filled from the mint when the rules store none. */\n sale: Sale;\n}\n\n/**\n * The largest number of addresses one getMultipleAccountsInfo call takes. Source:\n * the Solana RPC reference for getMultipleAccounts.\n */\nconst ACCOUNTS_PER_CALL = 100;\n\n/**\n * The parts of a DBC transfer hook pool this reads. Source: the\n * `transferHookPool` account and `poolState` type in the DBC SDK's IDL, offsets\n * counted from the start of the account; ARCHITECTURE.md, \"Offsets inside the\n * pool account\", agrees on base_mint.\n */\nconst HOOK_POOL_DISCRIMINATOR = Uint8Array.from([237, 219, 184, 23, 42, 189, 169, 35]);\nconst HOOK_POOL_SIZE = 424;\nconst POOL_BASE_MINT_OFFSET = 136;\n/** Zero until the trade that fills the curve moves it on. It never moves back. */\nconst POOL_MIGRATION_PROGRESS_OFFSET = 308;\n\n/** The Clock sysvar: slot, epoch start, epoch, leader schedule epoch, then Unix time. */\nconst CLOCK_UNIX_TIMESTAMP_OFFSET = 32;\n\nasync function readAccounts(\n connection: Connection,\n addresses: PublicKey[]\n): Promise<(AccountInfo<Uint8Array> | null)[]> {\n const found: (AccountInfo<Uint8Array> | null)[] = [];\n for (let start = 0; start < addresses.length; start += ACCOUNTS_PER_CALL) {\n const chunk = addresses.slice(start, start + ACCOUNTS_PER_CALL);\n const infos = await connection.getMultipleAccountsInfo(chunk);\n if (infos.length !== chunk.length) {\n throw new Error(\n `asked the node for ${chunk.length} accounts and it answered with ${infos.length}`\n );\n }\n found.push(...infos);\n }\n return found;\n}\n\nfunction sameBytes(left: Uint8Array, right: Uint8Array): boolean {\n return left.length === right.length && left.every((byte, index) => byte === right[index]);\n}\n\n/** Null unless these bytes are a DBC transfer hook pool selling this mint. */\nfunction poolGraduated(mint: PublicKey, info: AccountInfo<Uint8Array> | null): boolean | null {\n if (\n info === null ||\n !info.owner.equals(DBC_PROGRAM_ID) ||\n info.data.length !== HOOK_POOL_SIZE ||\n !sameBytes(info.data.subarray(0, 8), HOOK_POOL_DISCRIMINATOR) ||\n !sameBytes(\n info.data.subarray(POOL_BASE_MINT_OFFSET, POOL_BASE_MINT_OFFSET + 32),\n mint.toBytes()\n )\n ) {\n return null;\n }\n return info.data[POOL_MIGRATION_PROGRESS_OFFSET] !== 0;\n}\n\n/**\n * The chain's Unix time, the clock the hook judges the offering period by.\n * This machine's clock stands in only when the node returns no Clock, which a\n * real node never does.\n */\nfunction chainNow(info: AccountInfo<Uint8Array> | null): number {\n if (info === null || info.data.length < CLOCK_UNIX_TIMESTAMP_OFFSET + 8) {\n return Math.floor(Date.now() / 1000);\n }\n const view = new DataView(info.data.buffer, info.data.byteOffset, info.data.byteLength);\n return Number(view.getBigInt64(CLOCK_UNIX_TIMESTAMP_OFFSET, true));\n}\n\nfunction isRunning(mint: PublicKey, info: AccountInfo<Uint8Array> | null): boolean {\n try {\n return mintRunsPangu(mint, info);\n } catch {\n return false;\n }\n}\n\n/**\n * Every Pangu sale on the chain with what a list page shows: the token's name\n * and symbol, whether it is running, graduated or past its offering period,\n * and the headline rules.\n *\n * Reads are batched: one scan for the rules (see `listSales`, whose skipping\n * and `onSkipped` apply here unchanged), then every mint and pool plus the\n * Clock sysvar in calls of 100 addresses. Fifty sales cost three calls. The\n * scan and the batch are separate calls, so a sale that changes between them\n * is shown as of two nearby moments.\n *\n * Nothing about one sale can stop the others being listed: a mint that cannot\n * be read shows no name and not running, and a pool that cannot be read shows\n * `graduated` as null. Throws only when the node refuses a call.\n */\nexport async function saleDirectory(\n connection: Connection,\n options: ListSalesOptions = {}\n): Promise<SaleDirectoryEntry[]> {\n const sales = await listSales(connection, options);\n const addresses = [SYSVAR_CLOCK_PUBKEY, ...sales.flatMap((sale) => [sale.mint, sale.pool])];\n const infos = await readAccounts(connection, addresses);\n const now = chainNow(infos[0] ?? null);\n\n return sales.map((listed, index) => {\n const mintInfo = infos[1 + index * 2] ?? null;\n const poolInfo = infos[2 + index * 2] ?? null;\n const decimals = listed.baseDecimals === 0 ? readMint(listed.mint, mintInfo)?.decimals : undefined;\n const sale = decimals === undefined ? listed : { ...listed, baseDecimals: decimals };\n const token = tokenInfoFromMint(sale.mint, mintInfo);\n return {\n mint: sale.mint,\n pool: sale.pool,\n name: token?.name ?? null,\n symbol: token?.symbol ?? null,\n running: isRunning(sale.mint, mintInfo),\n graduated: poolGraduated(sale.mint, poolInfo),\n offeringOver: saleStanding(sale, [], now).offeringOver,\n hasBand: sale.hasBand,\n accessMode: sale.accessMode,\n quoteMint: sale.quoteMint,\n endsAt: sale.endsAt,\n buyers: sale.buyers,\n issuer: sale.issuer,\n sale,\n };\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 { Buffer } from \"buffer\";\nimport {\n PublicKey,\n SYSVAR_CLOCK_PUBKEY,\n SystemProgram,\n TransactionInstruction,\n type AccountMeta,\n type Connection,\n} from \"@solana/web3.js\";\nimport { attestationAddress } from \"./addresses.js\";\nimport { SAS_PROGRAM_ID, SEEDS } from \"./constants.js\";\nimport {\n PanguInputError,\n requireRealPublicKey,\n requireWholeNumber,\n} from \"./inputs.js\";\n\n/*\n * Instructions and reads for the Solana Attestation Service: what a verifier\n * needs to run a Pangu credential-mode sale. Open a credential, open a schema\n * under it, attest a wallet, revoke it by closing the attestation, and read\n * back what has been issued.\n *\n * Built by hand rather than through the service's own `sas-lib`, which is\n * generated for `@solana/kit` v2 while this package and everything that uses it\n * is web3.js 1.x. Every discriminator, account order and argument encoding is\n * copied from the service's source: `program/src/entrypoint.rs` for the\n * discriminators, `program/src/instructions.rs` for the account lists, and each\n * processor's `process_instruction_data` for the argument bytes. The same bytes\n * are proven against the real service in\n * packages/program/fork-tests/life-credential.ts.\n */\n\nconst CREATE_CREDENTIAL = 0;\nconst CREATE_SCHEMA = 1;\nconst CREATE_ATTESTATION = 6;\nconst CLOSE_ATTESTATION = 7;\n\n/** The service derives a schema address with its version as the last seed. */\nconst FIRST_SCHEMA_VERSION = 1;\n\n/** A program address seed is at most 32 bytes, and a name is used as one. */\nconst MAX_NAME_BYTES = 32;\n\n/** sas.rs MAX_AUTHORIZED_SIGNERS: Pangu refuses every buy against a longer list. */\nconst MAX_AUTHORIZED_SIGNERS = 64;\n\n/** The service's layout code for one unsigned byte. */\nconst LAYOUT_U8 = 0;\n\n/**\n * The schema a Pangu sale is written for: one byte, named \"verified\".\n *\n * Pangu never reads an attestation's data. It reads who the attestation is\n * about, who signed it, and when it runs out (programs/pangu/src/sas.rs), so\n * the smallest shape the service accepts is the right one. The service checks\n * every attestation's data against its schema's layout, which is why an\n * attestation defaults to the one byte this layout expects.\n */\nexport const VERIFIED_SCHEMA: {\n readonly layout: readonly number[];\n readonly fieldNames: readonly string[];\n readonly attestationData: readonly number[];\n} = {\n layout: [LAYOUT_U8],\n fieldNames: [\"verified\"],\n attestationData: [1],\n};\n\nexport interface CreateCredentialInput {\n /** Pays the rent. May be the authority. */\n payer: PublicKey;\n /** Runs the credential and signs. The address is derived from it and the name. */\n authority: PublicKey;\n name: string;\n /** The keys allowed to attest under this credential, one to 64 of them. */\n signers: PublicKey[];\n}\n\nexport interface CreateSchemaInput {\n payer: PublicKey;\n /** The credential's authority, who alone can add a schema to it. */\n authority: PublicKey;\n credential: PublicKey;\n name: string;\n description: string;\n /** The service's layout codes, one per field. Defaults to VERIFIED_SCHEMA. */\n layout?: readonly number[];\n fieldNames?: readonly string[];\n}\n\nexport interface CreateAttestationInput {\n payer: PublicKey;\n /** One of the credential's signers. Pangu checks it is still on the list at every buy. */\n authorizedSigner: PublicKey;\n credential: PublicKey;\n schema: PublicKey;\n /**\n * The buyer. Used as the attestation's nonce, which is the convention Pangu\n * requires: the hook derives the attestation address from the buying wallet\n * and refuses an attestation about anyone else.\n */\n wallet: PublicKey;\n /** Unix seconds at which the attestation runs out. Zero means it never does. */\n expiry: number;\n /** Bytes matching the schema's layout. Defaults to VERIFIED_SCHEMA's one byte. */\n data?: Uint8Array | readonly number[];\n}\n\nfunction meta(pubkey: PublicKey, isSigner: boolean, isWritable: boolean): AccountMeta {\n return { pubkey, isSigner, isWritable };\n}\n\nfunction u32(value: number): Buffer {\n const bytes = Buffer.alloc(4);\n bytes.writeUInt32LE(value);\n return bytes;\n}\n\nfunction lengthPrefixed(bytes: Uint8Array): Buffer {\n return Buffer.concat([u32(bytes.length), Buffer.from(bytes)]);\n}\n\nfunction requireName(value: unknown, field: string): Buffer {\n if (typeof value !== \"string\" || value.length === 0) {\n throw new PanguInputError(`${field} must be a name that is not empty`);\n }\n const bytes = Buffer.from(value, \"utf8\");\n if (bytes.length > MAX_NAME_BYTES) {\n throw new PanguInputError(\n `${field} must be at most ${MAX_NAME_BYTES} bytes, because it is part of an address, got ${bytes.length}`\n );\n }\n return bytes;\n}\n\nfunction requireText(value: unknown, field: string): Buffer {\n if (typeof value !== \"string\") {\n throw new PanguInputError(`${field} must be text`);\n }\n return Buffer.from(value, \"utf8\");\n}\n\nfunction requireBytes(value: unknown, field: string): Buffer {\n if (value instanceof Uint8Array) {\n return Buffer.from(value);\n }\n if (\n Array.isArray(value) &&\n value.every((byte) => Number.isInteger(byte) && byte >= 0 && byte <= 255)\n ) {\n return Buffer.from(value);\n }\n throw new PanguInputError(`${field} must be bytes`);\n}\n\n/** A credential's address. Seeds \"credential\", the authority and the name. */\nexport function credentialAddress(authority: PublicKey, name: string): PublicKey {\n return PublicKey.findProgramAddressSync(\n [\n Buffer.from(SEEDS.credential),\n requireRealPublicKey(authority, \"authority\").toBuffer(),\n requireName(name, \"name\"),\n ],\n SAS_PROGRAM_ID\n )[0];\n}\n\n/** A schema's first version. Seeds \"schema\", the credential, the name and the version byte. */\nexport function schemaAddress(credential: PublicKey, name: string): PublicKey {\n return PublicKey.findProgramAddressSync(\n [\n Buffer.from(SEEDS.schema),\n requireRealPublicKey(credential, \"credential\").toBuffer(),\n requireName(name, \"name\"),\n Buffer.from([FIRST_SCHEMA_VERSION]),\n ],\n SAS_PROGRAM_ID\n )[0];\n}\n\n/**\n * Opens a credential on the attestation service: a named verifier with a list\n * of keys allowed to attest under it.\n *\n * Throws PanguInputError for an empty or over-long name, no signers, a repeated\n * signer, or more signers than Pangu will read. Sends nothing.\n */\nexport function createCredentialInstruction(\n input: CreateCredentialInput\n): TransactionInstruction {\n const payer = requireRealPublicKey(input.payer, \"payer\");\n const authority = requireRealPublicKey(input.authority, \"authority\");\n const name = requireName(input.name, \"name\");\n if (!Array.isArray(input.signers) || input.signers.length === 0) {\n throw new PanguInputError(\"signers must hold at least one key, or nobody can attest\");\n }\n if (input.signers.length > MAX_AUTHORIZED_SIGNERS) {\n throw new PanguInputError(\n `signers must hold at most ${MAX_AUTHORIZED_SIGNERS} keys, Pangu refuses every buy against a longer list, got ${input.signers.length}`\n );\n }\n const signers = input.signers.map((signer, index) =>\n requireRealPublicKey(signer, `signers[${index}]`)\n );\n if (new Set(signers.map((signer) => signer.toBase58())).size !== signers.length) {\n throw new PanguInputError(\"signers must not repeat a key\");\n }\n\n return new TransactionInstruction({\n programId: SAS_PROGRAM_ID,\n keys: [\n meta(payer, true, true),\n meta(credentialAddress(authority, input.name), false, true),\n meta(authority, true, false),\n meta(SystemProgram.programId, false, false),\n ],\n data: Buffer.concat([\n Buffer.from([CREATE_CREDENTIAL]),\n lengthPrefixed(name),\n u32(signers.length),\n ...signers.map((signer) => signer.toBuffer()),\n ]),\n });\n}\n\n/**\n * Opens the first version of a schema under a credential. Only the credential's\n * authority can send it.\n *\n * Throws PanguInputError for an empty or over-long name, an empty layout, a\n * layout code outside one byte, or a field name list that does not match the\n * layout one for one. Sends nothing.\n */\nexport function createSchemaInstruction(input: CreateSchemaInput): TransactionInstruction {\n const payer = requireRealPublicKey(input.payer, \"payer\");\n const authority = requireRealPublicKey(input.authority, \"authority\");\n const credential = requireRealPublicKey(input.credential, \"credential\");\n const name = requireName(input.name, \"name\");\n const description = requireText(input.description, \"description\");\n const layout = requireBytes(input.layout ?? VERIFIED_SCHEMA.layout, \"layout\");\n if (layout.length === 0) {\n throw new PanguInputError(\"layout must name at least one field\");\n }\n const fieldNames = input.fieldNames ?? VERIFIED_SCHEMA.fieldNames;\n if (!Array.isArray(fieldNames) || fieldNames.length !== layout.length) {\n throw new PanguInputError(\n `fieldNames must name every field in the layout, one each: the layout has ${layout.length}`\n );\n }\n const fields = fieldNames.map((field, index) => requireText(field, `fieldNames[${index}]`));\n\n return new TransactionInstruction({\n programId: SAS_PROGRAM_ID,\n keys: [\n meta(payer, true, true),\n meta(authority, true, false),\n meta(credential, false, false),\n meta(schemaAddress(credential, input.name), false, true),\n meta(SystemProgram.programId, false, false),\n ],\n data: Buffer.concat([\n Buffer.from([CREATE_SCHEMA]),\n lengthPrefixed(name),\n lengthPrefixed(description),\n lengthPrefixed(layout),\n u32(fields.length),\n ...fields.map((field) => lengthPrefixed(field)),\n ]),\n });\n}\n\n/**\n * Attests one wallet under a credential and schema, with the wallet as the\n * nonce, so the attestation lands at the one address Pangu's hook derives for\n * that buyer.\n *\n * The expiry is unix seconds; zero means never. The service checks the signer\n * is on the credential's list at this moment and never again, which is why\n * Pangu checks it again on every buy. Throws PanguInputError for a missing key,\n * the all zero wallet, a negative or fractional expiry, or data that is not\n * bytes. Sends nothing.\n */\nexport function createAttestationInstruction(\n input: CreateAttestationInput\n): TransactionInstruction {\n const payer = requireRealPublicKey(input.payer, \"payer\");\n const authorizedSigner = requireRealPublicKey(input.authorizedSigner, \"authorizedSigner\");\n const credential = requireRealPublicKey(input.credential, \"credential\");\n const schema = requireRealPublicKey(input.schema, \"schema\");\n const wallet = requireRealPublicKey(input.wallet, \"wallet\");\n const expiry = requireWholeNumber(input.expiry, \"expiry\", 0, Number.MAX_SAFE_INTEGER);\n const data = requireBytes(input.data ?? VERIFIED_SCHEMA.attestationData, \"data\");\n\n const expiryBytes = Buffer.alloc(8);\n expiryBytes.writeBigInt64LE(BigInt(expiry));\n\n return new TransactionInstruction({\n programId: SAS_PROGRAM_ID,\n keys: [\n meta(payer, true, true),\n meta(authorizedSigner, true, false),\n meta(credential, false, false),\n meta(schema, false, false),\n meta(attestationAddress(credential, schema, wallet), false, true),\n meta(SystemProgram.programId, false, false),\n ],\n data: Buffer.concat([\n Buffer.from([CREATE_ATTESTATION]),\n wallet.toBuffer(),\n lengthPrefixed(data),\n expiryBytes,\n ]),\n });\n}\n\n/** The service's event authority, which the closing instruction names. Seed \"__event_authority\". */\nfunction eventAuthorityAddress(): PublicKey {\n return PublicKey.findProgramAddressSync([Buffer.from(\"__event_authority\")], SAS_PROGRAM_ID)[0];\n}\n\nexport interface CloseAttestationInput {\n /** Receives the attestation's rent. The verifier, when the verifier revokes. */\n payer: PublicKey;\n /** One of the credential's signers right now. Not necessarily the one who issued it. */\n authorizedSigner: PublicKey;\n credential: PublicKey;\n schema: PublicKey;\n /** The wallet the attestation is about, which is its nonce. */\n wallet: PublicKey;\n}\n\n/**\n * Revokes a wallet's credential by closing its attestation, the only\n * revocation the service has. Pangu sees it at the next buy: the account is\n * gone, so the buy is refused with CredentialInvalid.\n *\n * The service pays the attestation's rent to the payer, checks the signer is on\n * the credential's list now, and refuses a tokenized attestation, which needs a\n * different instruction. Throws PanguInputError for a missing key or the all\n * zero wallet. Sends nothing.\n */\nexport function closeAttestationInstruction(input: CloseAttestationInput): TransactionInstruction {\n const payer = requireRealPublicKey(input.payer, \"payer\");\n const authorizedSigner = requireRealPublicKey(input.authorizedSigner, \"authorizedSigner\");\n const credential = requireRealPublicKey(input.credential, \"credential\");\n const schema = requireRealPublicKey(input.schema, \"schema\");\n const wallet = requireRealPublicKey(input.wallet, \"wallet\");\n\n // Account order from `program/src/processor/close_attestation.rs`, which\n // destructures exactly these seven. The last is the service itself, which it\n // checks before it calls its own event instruction.\n return new TransactionInstruction({\n programId: SAS_PROGRAM_ID,\n keys: [\n meta(payer, true, true),\n meta(authorizedSigner, true, false),\n meta(credential, false, false),\n meta(attestationAddress(credential, schema, wallet), false, true),\n meta(eventAuthorityAddress(), false, false),\n meta(SystemProgram.programId, false, false),\n meta(SAS_PROGRAM_ID, false, false),\n ],\n data: Buffer.from([CLOSE_ATTESTATION]),\n });\n}\n\n/**\n * Where a wallet stands with one verifier, judged the way Pangu's hook judges\n * the attestation itself: there and in date, there and run out, or not there.\n */\nexport type CredentialStanding = \"valid\" | \"expired\" | \"absent\";\n\n/** One credential a verifier has issued, as `listAttestations` reads it. */\nexport interface IssuedCredential {\n /** The attestation account. */\n address: PublicKey;\n /** The wallet it is about, read from the nonce. */\n wallet: PublicKey;\n /** The key that signed it into existence. */\n signer: PublicKey;\n /** Unix seconds at which it runs out, or zero for never. */\n expiry: number;\n /**\n * Unix seconds of the transaction that opened this attestation, or null when\n * it was not found in the account's recent history. The service stores no\n * date, so this comes from the transaction history.\n */\n created: number | null;\n /** Judged against the chain's own clock at the time of the read. */\n standing: Exclude<CredentialStanding, \"absent\">;\n}\n\nconst ACCOUNT_ATTESTATION = 2;\nconst ATTESTATION_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 PUBKEY_BYTES = 32;\n\n/** Base58 of the single byte 0x02 that opens every attestation account. */\nconst ATTESTATION_DISCRIMINATOR_BASE58 = \"3\";\n\n/** The clock sysvar's unix_timestamp, after slot, epoch start, epoch and leader schedule epoch. */\nconst CLOCK_UNIX_TIMESTAMP_OFFSET = 32;\n\n/** How far back an attestation's history is searched for the transaction that opened it. */\nconst CREATED_SIGNATURES = 20;\nconst CREATED_TRANSACTIONS = 5;\n\ninterface DecodedAttestation {\n nonce: PublicKey;\n credential: PublicKey;\n schema: PublicKey;\n signer: PublicKey;\n expiry: number;\n}\n\nfunction readKey(data: Uint8Array, offset: number): PublicKey | null {\n return offset >= 0 && offset + PUBKEY_BYTES <= data.length\n ? new PublicKey(data.subarray(offset, offset + PUBKEY_BYTES))\n : null;\n}\n\n/**\n * Reads an attestation the way programs/pangu/src/sas.rs does, every field\n * bounds checked. Null for anything that is not a well formed attestation owned\n * by the service, which the callers treat as not there, the same way the hook\n * fails closed.\n */\nfunction decodeAttestation(owner: PublicKey, data: Uint8Array): DecodedAttestation | null {\n if (!owner.equals(SAS_PROGRAM_ID) || data.length < ATTESTATION_DATA_OFFSET) {\n return null;\n }\n if (data[0] !== ACCOUNT_ATTESTATION) {\n return null;\n }\n const view = new DataView(data.buffer, data.byteOffset, data.length);\n const signerOffset = ATTESTATION_DATA_OFFSET + view.getUint32(ATTESTATION_DATA_LEN_OFFSET, true);\n const signer = readKey(data, signerOffset);\n const expiryOffset = signerOffset + PUBKEY_BYTES;\n if (signer === null || expiryOffset + 8 > data.length) {\n return null;\n }\n return {\n nonce: readKey(data, ATTESTATION_NONCE_OFFSET) as PublicKey,\n credential: readKey(data, ATTESTATION_CREDENTIAL_OFFSET) as PublicKey,\n schema: readKey(data, ATTESTATION_SCHEMA_OFFSET) as PublicKey,\n signer,\n expiry: Number(view.getBigInt64(expiryOffset, true)),\n };\n}\n\n/** Zero never runs out, as sas.rs NEVER_EXPIRES says; any other runs out once the clock reaches it. */\nfunction standingOf(expiry: number, now: number): \"valid\" | \"expired\" {\n return expiry !== 0 && expiry <= now ? \"expired\" : \"valid\";\n}\n\nfunction clockTime(data: Uint8Array | undefined): number {\n if (data === undefined || data.length < CLOCK_UNIX_TIMESTAMP_OFFSET + 8) {\n throw new Error(\"the node returned no clock, so no credential can be judged in or out of date\");\n }\n const view = new DataView(data.buffer, data.byteOffset, data.length);\n return Number(view.getBigInt64(CLOCK_UNIX_TIMESTAMP_OFFSET, true));\n}\n\n/**\n * The time of the newest transaction that opened this attestation address.\n *\n * Newest, because a wallet revoked and issued again has the older opening in\n * its history as well. An opening is a transaction in which the address went\n * from no lamports to some. Only the latest few are read, so a wallet that has\n * bought many times since may come back null.\n */\nasync function openedAt(connection: Connection, address: PublicKey): Promise<number | null> {\n const signatures = await connection.getSignaturesForAddress(\n address,\n { limit: CREATED_SIGNATURES },\n \"confirmed\"\n );\n let read = 0;\n for (const entry of signatures) {\n if (entry.err !== null) {\n continue;\n }\n if (read === CREATED_TRANSACTIONS) {\n break;\n }\n read += 1;\n const detail = await connection.getTransaction(entry.signature, {\n commitment: \"confirmed\",\n maxSupportedTransactionVersion: 0,\n });\n if (detail === null || detail.meta === null || detail.meta === undefined) {\n continue;\n }\n const keys = detail.transaction.message\n .getAccountKeys({ accountKeysFromLookups: detail.meta.loadedAddresses })\n .keySegments()\n .flat();\n const index = keys.findIndex((key) => key.equals(address));\n if (\n index >= 0 &&\n detail.meta.preBalances[index] === 0 &&\n (detail.meta.postBalances[index] ?? 0) > 0\n ) {\n return detail.blockTime ?? entry.blockTime ?? null;\n }\n }\n return null;\n}\n\n/**\n * Every credential issued under one credential and schema, in no particular\n * order, each judged against the chain's clock.\n *\n * One scan of the service's accounts, filtered by the node on the attestation\n * discriminator, the credential and the schema. An attestation that does not\n * sit at the address its own nonce derives is left out: Pangu's hook would never\n * find it, so it approves nobody. Then, per attestation, a short read of its\n * history for the date it was opened, so the cost grows with the list. An RPC\n * that refuses getProgramAccounts throws rather than returning a short list.\n */\nexport async function listAttestations(\n connection: Connection,\n credential: PublicKey,\n schema: PublicKey\n): Promise<IssuedCredential[]> {\n const credentialKey = requireRealPublicKey(credential, \"credential\");\n const schemaKey = requireRealPublicKey(schema, \"schema\");\n const accounts = await connection.getProgramAccounts(SAS_PROGRAM_ID, {\n commitment: \"confirmed\",\n filters: [\n { memcmp: { offset: 0, bytes: ATTESTATION_DISCRIMINATOR_BASE58 } },\n { memcmp: { offset: ATTESTATION_CREDENTIAL_OFFSET, bytes: credentialKey.toBase58() } },\n { memcmp: { offset: ATTESTATION_SCHEMA_OFFSET, bytes: schemaKey.toBase58() } },\n ],\n });\n const clock = await connection.getAccountInfo(SYSVAR_CLOCK_PUBKEY, \"confirmed\");\n const now = clockTime(clock?.data);\n\n const issued: IssuedCredential[] = [];\n for (const entry of accounts) {\n const decoded = decodeAttestation(entry.account.owner, entry.account.data);\n if (\n decoded === null ||\n !decoded.credential.equals(credentialKey) ||\n !decoded.schema.equals(schemaKey) ||\n !attestationAddress(credentialKey, schemaKey, decoded.nonce).equals(entry.pubkey)\n ) {\n continue;\n }\n issued.push({\n address: entry.pubkey,\n wallet: decoded.nonce,\n signer: decoded.signer,\n expiry: decoded.expiry,\n created: await openedAt(connection, entry.pubkey),\n standing: standingOf(decoded.expiry, now),\n });\n }\n return issued;\n}\n\n/**\n * Whether a wallet holds a credential from this verifier right now: valid,\n * expired, or absent. Absent covers revoked, never issued, and anything at the\n * address that is not a well formed attestation about this wallet.\n *\n * Reads the attestation and the chain's clock in one call. Not checked here:\n * whether the key that signed it is still on the credential's list, which\n * Pangu also checks at every buy.\n */\nexport async function credentialStatus(\n connection: Connection,\n credential: PublicKey,\n schema: PublicKey,\n wallet: PublicKey\n): Promise<CredentialStanding> {\n const credentialKey = requireRealPublicKey(credential, \"credential\");\n const schemaKey = requireRealPublicKey(schema, \"schema\");\n const walletKey = requireRealPublicKey(wallet, \"wallet\");\n const [attestation, clock] = await connection.getMultipleAccountsInfo(\n [attestationAddress(credentialKey, schemaKey, walletKey), SYSVAR_CLOCK_PUBKEY],\n \"confirmed\"\n );\n const now = clockTime(clock?.data);\n if (attestation === null || attestation === undefined) {\n return \"absent\";\n }\n const decoded = decodeAttestation(attestation.owner, attestation.data);\n if (\n decoded === null ||\n !decoded.nonce.equals(walletKey) ||\n !decoded.credential.equals(credentialKey) ||\n !decoded.schema.equals(schemaKey)\n ) {\n return \"absent\";\n }\n return standingOf(decoded.expiry, now);\n}\n"],"mappings":"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","names":["PublicKey","PublicKey","PublicKey","SYSVAR_CLOCK_PUBKEY","unpackMint","unpackMint","CLOCK_UNIX_TIMESTAMP_OFFSET","SYSVAR_CLOCK_PUBKEY","PublicKey","PublicKey","Buffer","PublicKey","SYSVAR_CLOCK_PUBKEY","SystemProgram","TransactionInstruction","meta","Buffer","PublicKey","TransactionInstruction","SystemProgram","CLOCK_UNIX_TIMESTAMP_OFFSET","SYSVAR_CLOCK_PUBKEY"]}
|
package/dist/price.d.mts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { VersionedTransaction, Signer, PublicKey, Connection } from '@solana/web3.js';
|
|
2
|
+
import { F as FeedId, S as Sale } from './accounts-BuD-oCcr.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Keeping a banded sale's price fresh.
|
|
6
|
+
*
|
|
7
|
+
* Node and server only. It reaches Pyth's Hermes service over the network with
|
|
8
|
+
* an API key, and it pulls in `@pythnetwork/pyth-solana-receiver`, so the web
|
|
9
|
+
* app calls it from a server route and never from the browser. The key would be
|
|
10
|
+
* in every browser bundle otherwise, and every Hermes read has needed one since
|
|
11
|
+
* 26 August 2026
|
|
12
|
+
* (https://docs.pyth.network/price-feeds/core/upgrade/preparing). Reading a price back is
|
|
13
|
+
* `readPrice` in the core entry point, which is browser safe.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** The environment variable the Hermes key is read from. Server side only. */
|
|
17
|
+
declare const API_KEY_VARIABLE = "PYTH_API_KEY";
|
|
18
|
+
/** The feed a refresh writes: taken off a sale, or given by hand. */
|
|
19
|
+
interface FeedChoice {
|
|
20
|
+
priceFeedId: FeedId;
|
|
21
|
+
/** Defaults to Pangu's own shard, the one its refresher writes. */
|
|
22
|
+
shard?: number;
|
|
23
|
+
}
|
|
24
|
+
interface RefreshPriceInput {
|
|
25
|
+
connection: Connection;
|
|
26
|
+
/** Who pays the fee. Anyone can: the payer is not part of the address. */
|
|
27
|
+
payer: PublicKey;
|
|
28
|
+
/** A sale read from the chain, or the feed by hand. */
|
|
29
|
+
sale?: Sale;
|
|
30
|
+
feed?: FeedChoice;
|
|
31
|
+
/**
|
|
32
|
+
* The Hermes API key. Defaults to `PYTH_API_KEY` in the environment, which is
|
|
33
|
+
* where it should live: it is never a value a browser or a caller passes in.
|
|
34
|
+
*/
|
|
35
|
+
apiKey?: string;
|
|
36
|
+
/** Another Hermes host, for a self-hosted one. */
|
|
37
|
+
hermesUrl?: string;
|
|
38
|
+
}
|
|
39
|
+
/** One transaction of a refresh, unsigned, with the keys it needs besides the payer. */
|
|
40
|
+
interface RefreshTransaction {
|
|
41
|
+
transaction: VersionedTransaction;
|
|
42
|
+
/** Ephemeral accounts the guardian-signed update is verified through. */
|
|
43
|
+
signers: Signer[];
|
|
44
|
+
}
|
|
45
|
+
interface RefreshPrice {
|
|
46
|
+
/**
|
|
47
|
+
* Unsigned, in order. The payer signs each one and sends them in this order:
|
|
48
|
+
* the update is posted into an encoded VAA account first and the price feed
|
|
49
|
+
* account is written from it second, and the pair does not fit in one
|
|
50
|
+
* transaction.
|
|
51
|
+
*/
|
|
52
|
+
transactions: RefreshTransaction[];
|
|
53
|
+
/** The one account this feed and shard write to, for reading back afterwards. */
|
|
54
|
+
priceAccount: PublicKey;
|
|
55
|
+
shard: number;
|
|
56
|
+
/** Lowercase hex, no prefix. */
|
|
57
|
+
feedId: string;
|
|
58
|
+
/** Every transaction's bytes added up, against a limit of 1232 each. */
|
|
59
|
+
bytes: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Builds the transactions that write a fresh stock price into the one account
|
|
63
|
+
* this sale reads.
|
|
64
|
+
*
|
|
65
|
+
* Anybody can send them and the payer is not one of the account's seeds, so the
|
|
66
|
+
* address never moves and a sale can name it before anyone has ever refreshed
|
|
67
|
+
* it. It takes two transactions, not one: the guardian-signed update has to be
|
|
68
|
+
* posted into an encoded VAA account before the price feed account can be
|
|
69
|
+
* written from it, and the pair does not fit in 1232 bytes. So a refresh cannot
|
|
70
|
+
* ride along with a buy; send it first and the buy straight after, inside the
|
|
71
|
+
* age the sale allows.
|
|
72
|
+
*
|
|
73
|
+
* The encoded VAA account is closed by the last transaction, which is the
|
|
74
|
+
* difference between a refresh costing about 35 thousand lamports and about
|
|
75
|
+
* 2.4 million (docs/measurements/price-band-pyth.md). The price feed account
|
|
76
|
+
* itself is a program address, it is not one of the accounts closed, and it
|
|
77
|
+
* stays where it is.
|
|
78
|
+
*
|
|
79
|
+
* Node and server only. Signs and sends nothing.
|
|
80
|
+
*
|
|
81
|
+
* Throws PanguInputError when neither a sale nor a feed is given, when the sale
|
|
82
|
+
* has no band, when there is no API key, or when Hermes refuses.
|
|
83
|
+
*/
|
|
84
|
+
declare function refreshPriceTransaction(input: RefreshPriceInput): Promise<RefreshPrice>;
|
|
85
|
+
|
|
86
|
+
export { API_KEY_VARIABLE, type FeedChoice, type RefreshPrice, type RefreshPriceInput, type RefreshTransaction, refreshPriceTransaction };
|