{"_id":"@apecover/core","_rev":"2-ceaa0a664c6b4ae67c3c2ea42084a9c4","name":"@apecover/core","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@apecover/core","version":"0.1.0","keywords":["solana","anchor","defi","insurance","memecoin","degen","sdk"],"license":"MIT","_id":"@apecover/core@0.1.0","maintainers":[{"name":"rider-0825","email":"khishchenkomykola@gmail.com"}],"homepage":"https://github.com/Vetted-Pro/degen-trade-insurance#readme","bugs":{"url":"https://github.com/Vetted-Pro/degen-trade-insurance/issues"},"dist":{"shasum":"095b4366a844d3bdae858079e7a465c852609924","tarball":"https://registry.npmjs.org/@apecover/core/-/core-0.1.0.tgz","fileCount":57,"integrity":"sha512-RGwiUT+/1ZsoaLZhh/uTkfI+tl7GvmDoz6vmjfmNkQh+k5KqZpkdZeNieqGcTuP1WpJSnnfTbImVZv3D57cIcw==","signatures":[{"sig":"MEUCICivO052pQ5shtc5Kt1ssAvlVm9XTsCetnSYqp1LIbKlAiEAuNiCoZU5VvnYfASt9ZfSYxp7DMniZ6jlTFB4+McfrfI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1721445},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./idl":"./dist/generated/degen_insurance.json","./schema":{"types":"./dist/schema.d.ts","default":"./dist/schema.js"},"./fixtures":{"types":"./dist/fixtures.d.ts","default":"./dist/fixtures.js"},"./package.json":"./package.json"},"gitHead":"5f090d4e1787c6d0b48ebc7b206cd174e64cd4fe","scripts":{"build":"tsc --build","clean":"rm -rf dist *.tsbuildinfo","prepack":"npm run clean && npm run build"},"_npmUser":{"name":"rider-0825","email":"khishchenkomykola@gmail.com"},"repository":{"url":"git+https://github.com/Vetted-Pro/degen-trade-insurance.git","type":"git","directory":"packages/sdk"},"_npmVersion":"11.6.2","description":"Client SDK for the Degen Trade Insurance program on Solana: PDA derivation, account decoding, premium quoting and eligibility checks","directories":{},"sideEffects":false,"_nodeVersion":"24.11.1","dependencies":{"bn.js":"^5.2.1","@noble/hashes":"^1.8.0","@apecover/common":"0.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@solana/web3.js":"^1.98.4","@coral-xyz/anchor":"^0.32.1","@solana/spl-token":"^0.4.15"},"peerDependencies":{"@solana/web3.js":"^1.98.4","@coral-xyz/anchor":"^0.32.1","@solana/spl-token":"^0.4.15"},"_npmOperationalInternal":{"tmp":"tmp/core_0.1.0_1786922926631_0.05106268847541284","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@apecover/core","version":"0.3.0","description":"Client SDK for ApeCover on Solana and Robinhood Chain: one adapter interface, PDAs and Anchor builders on Solana, contract calldata on EVM, and chain-free premium quoting","keywords":["solana","anchor","evm","robinhood","defi","insurance","memecoin","degen","sdk"],"license":"MIT","homepage":"https://github.com/Vetted-Pro/degen-trade-insurance#readme","repository":{"type":"git","url":"git+https://github.com/Vetted-Pro/degen-trade-insurance.git","directory":"packages/sdk"},"bugs":{"url":"https://github.com/Vetted-Pro/degen-trade-insurance/issues"},"type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./solana":{"types":"./dist/solana.d.ts","default":"./dist/solana.js"},"./evm":{"types":"./dist/evm.d.ts","default":"./dist/evm.js"},"./fixtures":{"types":"./dist/fixtures.d.ts","default":"./dist/fixtures.js"},"./schema":{"types":"./dist/schema.d.ts","default":"./dist/schema.js"},"./evm-attestation":{"types":"./dist/evm-attestation.d.ts","default":"./dist/evm-attestation.js"},"./idl":"./dist/generated/degen_insurance.json","./package.json":"./package.json"},"sideEffects":false,"engines":{"node":">=20"},"publishConfig":{"access":"public"},"scripts":{"build":"tsc --build","clean":"rm -rf dist *.tsbuildinfo","prepack":"npm run clean && npm run build"},"dependencies":{"@apecover/common":"0.3.0","@noble/hashes":"^1.8.0","bn.js":"^5.2.1"},"peerDependencies":{"@coral-xyz/anchor":"^0.32.1","@solana/spl-token":"^0.4.15","@solana/web3.js":"^1.98.4"},"devDependencies":{"@coral-xyz/anchor":"^0.32.1","@solana/spl-token":"^0.4.15","@solana/web3.js":"^1.98.4"},"gitHead":"35b422cba29d2dce62b69624c212b3fff979e168","_id":"@apecover/core@0.3.0","_nodeVersion":"24.11.1","_npmVersion":"11.6.2","dist":{"integrity":"sha512-QBdaR+RcPEGfkZpxc+fekHk8rVNPpq/U5zAqrBXwHfjW+kA+hN5zgD1wGaLe+yXsTYYS5AOTB2/K+J12/tK7PQ==","shasum":"840dfc921512a25e6234ebbf8b7b05b928df13a6","tarball":"https://registry.npmjs.org/@apecover/core/-/core-0.3.0.tgz","fileCount":81,"unpackedSize":2028898,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD7KQHw+xsZkFDfkHH1GCnGhY5XQKa/U57kFdQTVX97KAIhAIL0c7fl5yQpT0PIh57gntXj/PKhtti5k0ay225NP4OV"}]},"_npmUser":{"name":"rider-0825","email":"khishchenkomykola@gmail.com"},"directories":{},"maintainers":[{"name":"rider-0825","email":"khishchenkomykola@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/core_0.3.0_1787748691064_0.558798561249044"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-16T23:28:46.521Z","modified":"2026-08-26T12:51:31.381Z","0.1.0":"2026-08-16T23:28:46.771Z","0.3.0":"2026-08-26T12:51:31.223Z"},"bugs":{"url":"https://github.com/Vetted-Pro/degen-trade-insurance/issues"},"license":"MIT","homepage":"https://github.com/Vetted-Pro/degen-trade-insurance#readme","keywords":["solana","anchor","evm","robinhood","defi","insurance","memecoin","degen","sdk"],"repository":{"type":"git","url":"git+https://github.com/Vetted-Pro/degen-trade-insurance.git","directory":"packages/sdk"},"description":"Client SDK for ApeCover on Solana and Robinhood Chain: one adapter interface, PDAs and Anchor builders on Solana, contract calldata on EVM, and chain-free premium quoting","maintainers":[{"name":"rider-0825","email":"khishchenkomykola@gmail.com"}],"readme":"# @apecover/core\n\nClient SDK for [ApeCover](https://github.com/Vetted-Pro/degen-trade-insurance) — a protocol that\npays out when a memecoin position collapses inside its coverage window — on **Solana** and on\n**Robinhood Chain**.\n\nEverything here is read-only or pure: address derivation, account decoding, calldata encoding, and\nthe premium and eligibility arithmetic. Nothing in this package signs or sends a transaction.\n\n## Entry points\n\nThe root imports **no chain runtime at all** — no `@solana/web3.js`, no Anchor, no EVM library. A\nbot that only wants to price a trade gets arithmetic and nothing else; the chain-specific halves\nare asked for by name.\n\n| Import                           | What it carries                                                        | Chain runtime    |\n| -------------------------------- | ---------------------------------------------------------------------- | ---------------- |\n| `@apecover/core`                 | premium quoting, eligibility, the adapter interface, branded addresses | none             |\n| `@apecover/core/solana`          | PDAs, Anchor instruction builders, account decoders                    | web3.js + Anchor |\n| `@apecover/core/evm`             | contract calldata, pool ids, derived selectors                         | none — see below |\n| `@apecover/core/evm-attestation` | the EIP-712 message the pool verifies                                  | none             |\n| `@apecover/core/schema`          | the IDL hash. Uses `node:crypto`, so never bundle it for a browser     | none             |\n| `@apecover/core/fixtures`        | test encoders, deliberately off any production import path             | web3.js          |\n\nThat split is a promise rather than a tree-shaking hope. A bundler _might_ drop an unused Solana\nhalf from an application build; it would never drop it for a Node process, which is what a trading\nbot is, and \"it depends on your bundler\" is not a property a package can promise. Two entry points\nis one it can — and `bundle.test.ts` holds it, by resolving the module graph from `@apecover/core`\nwith esbuild and failing if a chain runtime appears in the metafile.\n\nComing from 0.2.0, where the root re-exported everything: the migration is one line per import,\nand `docs/MIGRATION-core-0.3.md` lists them.\n\n```bash\n# Solana — both peers, for the reason below\nnpm install @apecover/core @coral-xyz/anchor @solana/web3.js\n\n# quoting only, or the EVM half\nnpm install @apecover/core\n```\n\n`@coral-xyz/anchor` and `@solana/web3.js` are **peer** dependencies on purpose. Both ship classes\nthat get compared structurally across package boundaries, and two copies on disk means two\ndistinct `PublicKey` and `BN` classes — a hazard this codebase has hit more than once. Declaring\nthem as peers means you get one copy: yours.\n\nThey are not marked optional, so npm will still fetch them for a project that only ever imports\n`@apecover/core/evm`. That costs install size and nothing else — no EVM code path loads them, which\nis the claim the bundle test checks.\n\n### One override you will probably need\n\n`@solana/web3.js@1.98.4` depends on `rpc-websockets@9.3.9`, which is CommonJS and `require()`s\n`uuid@^14` — and uuid 14 is ESM-only. On a fresh install that combination throws before any of\nyour code runs:\n\n```\nError: require() of ES Module .../uuid/dist-node/index.js\nfrom .../rpc-websockets/dist/index.cjs not supported\n```\n\nIt is upstream of this SDK and it breaks `import '@solana/web3.js'` on its own. Until web3.js\nships a fix, pin uuid to its last CommonJS major:\n\n```json\n{\n  \"overrides\": {\n    \"uuid\": \"^9.0.1\"\n  }\n}\n```\n\nThen delete `node_modules` and `package-lock.json` and reinstall — npm will not re-resolve a\nnested copy that a stale lockfile already pinned.\n\n## Deployments\n\n| chain                           | deployment                                                                                                                                        |\n| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Solana devnet                   | [`4xhLjuNsJPE4XssmJTYhL7d5VHhHTs4S8yKSVXSbxnU8`](https://explorer.solana.com/address/4xhLjuNsJPE4XssmJTYhL7d5VHhHTs4S8yKSVXSbxnU8?cluster=devnet) |\n| Solana mainnet                  | not deployed                                                                                                                                      |\n| Robinhood Chain testnet (46630) | [`0x932e54A4929f156154dABa61d30abe5172542370`](https://explorer.testnet.chain.robinhood.com/address/0x932e54A4929f156154dABa61d30abe5172542370)   |\n| Robinhood Chain (4663)          | not deployed, and disabled in the registry until `docs/MAINNET_GATE.md` is met                                                                    |\n\n**The EVM half has a testnet pool to talk to.** It is complete and tested against the Solidity\nsources, and the pool proxy above is deployed and verified on 46630; nothing is deployed on\nmainnet 4663. Whether a particular pool will underwrite a particular trade is a live question\nabout that pool, not about the chain — read its state before you rely on it. What the _chain_\nsupports is data rather than prose: `@apecover/common` carries it in a registry, so a client asks\ninstead of finding out:\n\n```ts\nimport { CHAIN_REGISTRY, isChainEnabled } from '@apecover/core';\n\nisChainEnabled('robinhood'); // false\nCHAIN_REGISTRY.robinhood.disabledReason; // why, in a sentence you can show a user\n```\n\n## Reading a pool\n\n```ts\nimport { Connection } from '@solana/web3.js';\nimport { fetchPool, utilizationBps } from '@apecover/core/solana';\n\nconst PROGRAM = '4xhLjuNsJPE4XssmJTYhL7d5VHhHTs4S8yKSVXSbxnU8';\nconst connection = new Connection('https://api.devnet.solana.com');\n\nconst pool = await fetchPool(connection, PROGRAM);\nif (pool === null) throw new Error('no pool on this cluster');\n\nconsole.log(pool.totalLiabilities); // '150000000'  — a string, always\nconsole.log(pool.graceSeconds); // 120\nconsole.log(utilizationBps(pool)); // 1500 → 15%\n```\n\nEvery lamport amount is a **decimal string**, never a number. A `u64` above 2^53 does not survive\n`Number()`, and a client that quietly rounds a pool's reserves is worse than one that fails to\nload. Convert with `BigInt(pool.totalLiabilities)` when you need arithmetic.\n\n`fetchPool` returns `null` — rather than throwing — when the pool account does not exist, because\npointing a client at a cluster where the program has not been initialised is a normal state that\ndeserves an empty screen, not an error boundary.\n\n## Quoting a premium before buying cover\n\n```ts\nimport { checkEligibility, quotePolicy, quoteSingleTrade } from '@apecover/core';\nimport { CoverageTier } from '@apecover/common';\n\nconst quote = quotePolicy(context, 300_000_000n, 10); // 0.3 SOL, a 10-trade pack\nquote.premium; // 15000000n  — 0.015 SOL at tier B's 5%\nquote.split; // { protocol, partner, underwriter, reserve } — sums to premium exactly\n```\n\nThe arithmetic mirrors `math.rs` field for field, including its rounding, so a premium shown to a\nuser is the premium the program will charge. It is the same worked example the product spec uses:\n0.3 SOL at 5% is 0.015 SOL.\n\n`checkEligibility` answers the question _before_ the user signs, and names the reason it refuses —\nmarket cap over the tier limit, trade size outside the pool's bounds, pool paused, or the pool\nlacking the capacity to reserve the liability.\n\n## Deriving addresses\n\n```ts\nimport {\n  findPool,\n  findPolicy,\n  findTrade,\n  findClaim,\n  poolAddress,\n} from '@apecover/core/solana';\n\nconst [pool] = findPool(programId); // native SOL settlement (ADR-0001)\nconst [policy] = findPolicy(programId, pool, owner, 0);\nconst [trade] = findTrade(programId, policy, 3);\nconst [claim] = findClaim(programId, trade);\n```\n\n## Two chains, one adapter\n\n`ChainAdapter` is the seam between the halves, and it lives in the chain-free root so that reading\nit costs no runtime. Two implementations, each binding the interface's generics to what its own\nsigner actually takes:\n\n```ts\nimport { solanaAdapter } from '@apecover/core/solana';\nimport { evmAdapter } from '@apecover/core/evm';\nimport { evmAddress } from '@apecover/core';\n\nconst sol = solanaAdapter({ programId, pool }); // ChainAdapter<TransactionInstruction, SolanaAddress>\nconst evm = evmAdapter({ chain: 'robinhood-testnet', pool: evmAddress(poolContract) }); // <EvmCall, EvmAddress>\n\nsol.addressFor({ kind: 'trade', policy, index: 3n }); // a base58 PDA\nevm.addressFor({ kind: 'trade', index: 3n }); // '3' — a mapping key, not an address\n```\n\nThere is no shared call type on purpose. A Solana instruction is a program id, an account list and\na data buffer; an EVM call is `{ to, data, value }`. Unifying them would produce a lowest common\ndenominator neither signer can use, so the adapter is generic in its call type instead, and a\ncaller that has narrowed to one chain holds the real type rather than a union to re-narrow.\n\nAddresses are generic for the same reason and buy something extra: they are **branded**, so\nhanding a `SolanaAddress` to an EVM builder is a compile error at the call site, with no runtime\ncheck to write and none to forget.\n\n`addressFor` returns whatever _identifies_ the thing on that chain, which is not always an address.\nOn Solana every object here is a PDA. On EVM one contract is one pool and a policy is a mapping\nkey, so the answer is the number — the same distinction the HTTP API draws, where `/trades/42` is\nwell formed on an EVM chain and malformed on Solana.\n\n### Ask what a chain can do; do not catch it\n\n```ts\nimport { capabilitiesFor } from '@apecover/core';\n\ncapabilitiesFor('solana').rent; // true  — accounts are pre-funded and refunded on close\ncapabilitiesFor('robinhood').approvals; // true  — ERC-20 allowances exist here and not on Solana\ncapabilitiesFor('robinhood').settlementLagSeconds; // 843, vs 0 on Solana\n```\n\nEvery field is a property of the **chain**, never of your pool, so reading one costs no round trip.\nA client that discovered the same differences by handling an exception would have to tell \"this\nchain cannot\" apart from \"this call failed\", and those two arrive identically.\n\n`settlementLagSeconds` is the one to actually budget against. It is `0` on Solana, where rolling a\n`confirmed` write back needs a supermajority fork. On 4663 it is `843` — the measured **peak** of\nhow far the `safe` tag stepped behind head, not an average, because the tag steps rather than\nlags, and 843 seconds is longer than a tier-A trade's entire coverage window.\n\n### No ABI, and no ABI library\n\nThe EVM half derives its selectors from signature strings at module load rather than pasting them,\nand encodes by hand because all but one argument on this path is statically sized. The exception is\n`registerTrade`'s `bytes signature`, whose offset is computed from the encoded head rather than\nwritten down. That keeps the package free of an ABI dependency — which matters, because a hard EVM\ndependency would make the chain-free root a lie for everyone who installs it. `evm.test.ts`\nreparses `IApeCoverPool.sol` and rebuilds each pool signature from the declaration, checks `TIER_ORDER`\nand the attestation tuple against `Types.sol`'s own declarations, and recomputes that offset from\nthem — so a parameter added on chain reddens a test here instead of producing calldata that reverts\nwith no reason attached.\n\n## Decoding accounts and events\n\n```ts\nimport { decodePoolState, camelKeys, plain, discriminantOf } from '@apecover/core/solana';\n```\n\n`decodePoolState(data)` decodes raw account bytes. The generic helpers behind it are exported too,\nbecause anything reading this program's accounts needs the same four steps:\n\n- `camelKeys` — the coder returns `rug_threshold_bps`, not `rugThresholdBps`\n- `plain` — `PublicKey` → base58, `BN` → decimal string, unit enum → its tag\n- `discriminantOf(typeName, value)` — a variant's on-chain number, by the IDL's declaration order,\n  returning `null` rather than 0 when it cannot place the tag. `TradeStatus::Registered` is 0, so\n  a fallback of 0 files an unreadable record in the bucket that flatters the pool.\n- `str` / `num` — read a field as a decimal string or a number, falling back rather than coercing\n\nThe vendored IDL is available directly, for building your own coders:\n\n```ts\nimport { IDL } from '@apecover/core';\nimport IDL_JSON from '@apecover/core/idl' with { type: 'json' };\n```\n\n## Test helpers\n\n```ts\nimport { encodeAccount } from '@apecover/core/fixtures';\n\nconst data = await encodeAccount('InsuredTrade', { status: { Paid: {} } });\n```\n\nEncodes a program account by walking the IDL — every declared field gets a zero value of the right\nshape and your overrides go on top, so the fixture is always exactly as wide as the account rather\nthan as wide as your assertions. Useful for testing a decoder without a validator.\n\nIt lives on a subpath rather than the main entry point deliberately: a test helper in the main\nnamespace is an invitation to reach for it in a production path.\n\n## Invariants worth knowing\n\nThe program enforces these, and this SDK's arithmetic assumes them:\n\n- liabilities never exceed the vault's usable balance times the pool's max utilisation\n- a payout is capped at both the tier's ratio of trade size and the pool's per-trade cap\n- premium splits sum to the premium exactly — no lamport is created or destroyed by rounding\n- a trade goes `Registered → (Claimed → Paid | Rejected) | Expired`, once\n\n## Licence\n\nMIT\n","readmeFilename":"README.md"}