@somnia-chain/contracts-sdk
v0.3.0
Published
Somnia contract addresses, ABIs and chain information, typed. Generated from the Somnia contract registry.
Downloads
438
Readme
@somnia-chain/contracts-sdk
Somnia contract addresses, ABIs and chain information, typed. Generated from the Somnia contract registry — the same records every Somnia deploy is reconciled against.
npm install @somnia-chain/contracts-sdkThe package is split by delivery mechanism, deliberately. Addresses and chain information are small and change on every deploy — they live in the root entry, ~170 kB of data. ABIs are megabytes that change only when contracts change — they ship one module per contract, so a client bundle carries exactly the ABIs it imports and a bundle that needs only addresses carries none.
Addresses and networks — the root entry
import { address, tryAddress, contracts, identify } from "@somnia-chain/contracts-sdk";
address("somnia-mainnet", "somnia-markets", "MarketsCore");
// throws on unknown names — the "this must exist" form; every slug and
// name is autocompleted and the address is a literal type
tryAddress("hideki-testnet", "somnia-markets", "MarketsCore"); // Address | null
// the "is it deployed here?" form — projects do not span every network
contracts("somnia-mainnet", "somnia-markets"); // enumerate, for admin screens
identify("somnia-mainnet", "0x1a47…"); // reverse lookup: project, name, kind
allContracts();
// every current deployment across every live network — the dashboard form.
// Retired networks and superseded deployments are excluded by default, so a
// wiped testnet's addresses cannot be rendered as current by forgetting to
// filter: { includeRetiredNetworks, includeSuperseded, project } to widen it.Entries carry address, kind, status, version, and contract — the
Solidity contract name, where a source stated one. kind and status are
unions (DeploymentKind, ContractStatus), not string.
Networks: networks (all, retired included), network(slug),
liveNetworks(), and toChain(slug, { rpcUrl }) for a viem-Chain-shaped
object — you supply the RPC URL, the registry deliberately records no public
endpoint. registryVersion says which commit the data came from.
Chain IDs are not unique
Networks are keyed by slug, never by chain id: a testnet regenesis reuses the chain id with none of the state, so one id can name two networks with different contracts at identical addresses.
networksByChainId(50383); // -> both hideki testnets — an array, deliberatelyABIs — typed per contract, or the whole corpus
// Build-time, typed, tree-shakeable: one module per contract.
import { SafeAbi } from "@somnia-chain/contracts-sdk/abi/somnia-accounts/Safe";
// as-const literal — viem infers function names and argument types
// Runtime, whole corpus (~1 MB — server/admin paths):
import { abiFor, abiByHash, verifyAbi, writeFunctions } from "@somnia-chain/contracts-sdk/abis";
abiFor("somnia-mainnet", "somnia-markets", "MarketsCore"); // Abi | null
abiByHash("sha256:…"); // historical ABIs too — decode an old tx correctly
verifyAbi("sha256:…", abi); // sha256 over key-sorted compact JSON — verify, don't trust filenames
writeFunctions("somnia-mainnet", "somnia-markets", "MarketsCore");
// all state-changing functions — allowlists are application policy, not deployment facts
allContractsWithAbi();
// allContracts() with each ABI resolved to `abiJson` — addresses, networks and
// ABIs in one call. Costs the whole corpus, which is why it lives here.Not every deployment has an ABI
abiFor returns null, and abiJson is null, for a real share of what the
registry holds — around half, concentrated in the testnets. That is a fact
about the records, not a gap in the package: the registry records a contract
name only where a broadcast log stated it or the repo declared one, and an ABI
is looked up by that name. Deployments created from a shared script as
per-asset instances — BTC_reader, ADA_oracle — name a role rather than a
contract, so they carry an address and no ABI. contract is set on exactly
the entries that have one, so it is the field to branch on.
Decoding calldata
Requires viem (optional peer dependency; only this entry needs it).
import { decodeCall, decodeBySelector } from "@somnia-chain/contracts-sdk/decode";
const call = decodeCall("somnia-mainnet", to, data);
// identifies the target, decodes against its recorded ABI, and recurses
// through Safe execTransaction / MultiSend, Multicall3 and upgradeToAndCall —
// what a signer staring at hex actually needs
if (call.status === "decoded") call.signature; // "transfer(address,uint256)"
else call.selector; // undecoded is a variant, not an error
decodeBySelector(data); // 4-byte fallback across every ABI the registry holdsVersioning
The package is a snapshot of the registry, and it is published when that snapshot changes rather than when someone remembers to publish it. The reconciliation lane compares the surface it would generate against the one the last release shipped, and cuts a patch version whenever addresses, ABIs or chain information moved — so a contract deployed today reaches npm on the next lane run. Minor and major versions are cut by hand, for API changes.
Update the dependency to pick up newly deployed contracts — nothing is fetched at runtime.
