LIQ Staking Module for Wire Network
npm install @wireio/stakeTypeScript / JavaScript SDK for the Outpost and Liquidity Staking (LIQ) protocol on the Wire Network.
It gives dApps a single façade (Staker) over Solana and EVM implementations, while still exposing
chain‑specific power features (Outpost, pretokens, SquadsX, validator tools, etc.).
Staker that selects the right chain client by chainId.getPortfolio view (native, liq, staked, $WIRE, yield, extras).getDepositFee, getDepositBuffer, getSystemAPY).extras.squadsX when constructing a Solana StakerConfig:ts
const cfg: StakerConfig = {
provider: solAdapter,
network: solNetwork,
pubKey: new WirePubKey(KeyType.ED, solAdapter.publicKey!.toBytes()),
extras: { squadsX: { multisigPDA: '', vaultIndex: 0 } },
};
`
- When present, every write call (deposit, withdraw, stake, unstake, buy) is wrapped as a Squads vault transaction via sendSquadsIxs, producing a proposal that you approve/execute in Squads.
- The Hub staking service persists the PDAs in localStorage (hub_squadsx_multisigpda, hub_squadsx_vaultindex) and reinitializes the Staker with Squads enabled; copy that pattern for multisig-first apps.Mental model
- Facade first: Use Staker everywhere; it routes to the right chain client and keeps the API identical.
- Base units only: All amounts are lamports/wei (no floats internally).
- Read-only vs write: If you omit provider/pubKey, clients spin up in read-only mode—perfect for tranche snapshots, APY, and portfolio lookups against public RPCs. Add a signer (provider + pubKey) to unlock writes (deposit/withdraw/stake/unstake/buy/register). The Hub service uses read-only configs to prefill dashboards before wallets connect, then re-initializes with signer configs once a wallet is present.
- State views: getPortfolio() is the fastest way to know “native, liq, staked, $WIRE, yield” plus handy PDAs/addresses.
- Snapshots: getTrancheSnapshot(chainId) powers price ladders, liquidity/utilization charts, and native USD hints.Supported networks (today)
- Solana: SolChainID.Mainnet, SolChainID.Devnet.
- EVM: EvmChainID.Ethereum, EvmChainID.Hoodi (testnet).The unified interface is chain-id driven:
new Staker(configs, selectedChainId) builds per-chain clients behind the scenes, and staker.setChain(chainId) swaps the active client. Adding future chains (e.g., Sui) only requires implementing IStakingClient and wiring its chainId into the router—no API changes for consuming apps.Installation
`bash
npm install @wireio/stake
`
Peer requirement: @wireio/core >=0.1.0 <0.4.0.Quick start: pick a chain, then call through
client`ts
import { Staker, StakerConfig, SolChainID, EvmChainID } from '@wireio/stake';
import { PublicKey as WirePubKey, KeyType } from '@wireio/core';
import { BaseSignerWalletAdapter } from '@solana/wallet-adapter-base';
import { ethers } from 'ethers';// ---- Solana example (wallet adapter) ----
const solAdapter: BaseSignerWalletAdapter = / connected wallet /;
const solCfg: StakerConfig = {
provider: solAdapter,
network: {
chainId: SolChainID.Devnet,
name: 'Wire Solana Devnet',
rpcUrls: ['https://...', 'wss://...'],
nativeCurrency: { symbol: 'SOL', decimals: 9 },
},
pubKey: new WirePubKey(KeyType.ED, solAdapter.publicKey!.toBytes()),
extras: { squadsX: { multisigPDA: '', vaultIndex: 0 } }, // optional
};
// ---- Ethereum example (browser provider) ----
const ethProvider = new ethers.providers.Web3Provider(window.ethereum);
const ethCfg: StakerConfig = {
provider: ethProvider,
network: {
chainId: EvmChainID.Ethereum,
name: 'Ethereum',
rpcUrls: ['https://...'],
nativeCurrency: { symbol: 'ETH', decimals: 18 },
},
};
const staker = new Staker([solCfg, ethCfg], SolChainID.Devnet); // default active chain
const client = staker.client; // typed staking client for the selected chain
`$3
Amounts are always base units (lamports / wei).
`ts
await client?.deposit(1_000_000_000n); // stake 1 SOL -> liqSOL (or 1e9 wei -> liqETH)
await client?.withdraw(500_000_000n); // liq -> native withdraw request
await client?.stake(200_000_000n); // stake liq into yield pool (Sol Outpost / ETH manager)
await client?.unstake(100_000_000n); // reverse stake (where supported)
await client?.buy(50_000_000n); // purchase WIRE pretokens with liq
const portfolio = await client?.getPortfolio(); // unified balance snapshot
`$3
- deposit(lamports): builds ix via DepositClient, optionally wraps in SquadsX vault tx, sends and confirms.
- withdraw(lamports): burns liqSOL and mints a withdrawal NFT receipt (payout later via operators).
- stake/unstake: interacts with Outpost (synd/desynd) to move liqSOL into/out of yield pool.
- buy(lamports): purchase $WIRE pretokens using liqSOL (Token-2022).
- Multisig: if extras.squadsX is set, write calls become Squads proposals (sendSquadsIxs).
- Portfolio extras include key PDAs (vault, reserve pool, user ATA) plus Outpost index/shares math.$3
- deposit(amountWei): via ConvertClient.performDeposit; returns tx hash.
- withdraw(amountWei): burns liqETH and enqueues withdrawal; receipts are NFTs.
- getPendingWithdraws() / claimWithdraw(tokenId): manage withdrawal queue.
- stake(amountWei): stakes liqETH; unstakePrelaunch(tokenId, recipient) handles prelaunch path.
- buy(amountWei): pretokens via PretokenClient.purchasePretokensWithLiqETH.
- validatorDeposit(): validator bond/lock helper.
- Portfolio includes native/liq/staked/$WIRE and yield (index/shares) when contracts expose them.Solana specifics
- Clients composed under the hood: DepositClient, DistributionClient, OutpostClient,
TokenClient, ValidatorLeaderboardClient, SolanaProgramService.
- SquadsX multisig: provide extras.squadsX to have deposits / stakes wrapped as vault
transactions (sendSquadsIxs).
- Outpost / Yield: getPortfolio() returns yield (index-scale math) and staked amounts; wire
reports pretokens (1e8 scale).
- Helpers: getDepositBuffer, getDepositFee, getSystemAPY, tranche snapshots via
getTrancheSnapshot(chainId).Ethereum specifics
- Uses ethers provider/signer; falls back to JSON RPC for read-only.
- Modules used: ConvertClient (deposit/withdraw), StakeClient, PretokenClient, OPPClient,
ReceiptClient (withdrawal NFTs), ValidatorClient.
- Additional endpoints:
- getPendingWithdraws() → pending withdrawal receipts.
- claimWithdraw(tokenId) → claim queued withdrawal by NFT id.
- unstakePrelaunch(tokenId, recipient) → prelaunch unstake path.
- validatorDeposit() → validator bond/lock flow.
- getTrancheSnapshot(chainId) → pretoken ladder view with price/supply growth.
- getOPPMessages(address?) and getEthStats() for operator/pay-rate data.Portfolio shape (all chains)
`ts
type Portfolio = {
native: { amount: bigint; symbol: string; decimals: number };
liq: { amount: bigint; symbol: string; decimals: number; ata?: PublicKey };
staked: { amount: bigint; symbol: string; decimals: number };
wire: { amount: bigint; symbol: string; decimals: number };
yield?: { currentIndex: bigint; indexScale: bigint; totalShares: bigint;
userShares: bigint; estimatedClaim?: bigint; estimatedYield?: bigint };
extras?: Record;
chainID: number;
};
`Error handling
- All write methods throw on failure; wrap with try/catch.
- Solana transaction failures include logs; Ethereum methods surface tx hashes for inspection.
- Passing provider is required for writes; read-only is supported for many getters.Using from a service (pattern)
Your staking.service.ts can simply forward to the selected client. The Wire Hub webapp
(wire-hub-webapp/src/app/_services/staking.service.ts) does this and adds read-only Outpost
clients, tranche/APY polling, SquadsX, and retryable portfolio refresh. Typical shape:
`ts
export class StakingService {
constructor(private staker: Staker) {}
deposit(amount: bigint) { return this.staker.client?.deposit(amount); }
withdraw(amount: bigint) { return this.staker.client?.withdraw(amount); }
stake(amount: bigint) { return this.staker.client?.stake(amount); }
unstake(amount: bigint) { return this.staker.client?.unstake(amount); }
buy(amount: bigint) { return this.staker.client?.buy(amount); }
portfolio() { return this.staker.client?.getPortfolio(); }
stats(chainId: number) { return this.staker.client?.getTrancheSnapshot(chainId); }
}
`
Switch chains at runtime with staker.setChain(chainId).Hub-specific extras you can reuse:
- Read-only bootstrap: configs with only
network to fetch tranche snapshots/APY before a wallet connects.
- APY helpers: getSystemAPY() per chain; normalize number/string/bigint shapes.
- Deposit buffer: getDepositBuffer({ balanceOverrideLamports }) to compute max-spendable.
- SquadsX multisig: store multisigPDA + vaultIndex (localStorage keys hub_squadsx_multisigpda, hub_squadsx_vaultindex) and pass via extras.squadsX so write calls become Squads proposals.
- ETH prelaunch/receipts: getPendingWithdraws, claimWithdraw(tokenId), unstakePrelaunch(tokenId, recipient), fetchPrelaunchReceipts.
- Tranche ladders: cache getTrancheSnapshot(chainId) per chain for dashboards (liquidity/utilization/arb spread).Portfolio fields (returned by
getPortfolio)
- native: wallet balance in base units; symbol/decimals from network.
- liq: liquid staking token balance (Token-2022 ATA on Sol; ERC-20 on EVM).
- staked: liq staked into Outpost (Sol) or staking manager (ETH).
- wire: pretoken balance (1e8 scale).
- yield: currentIndex, indexScale, totalShares, userShares, estimatedClaim, estimatedYield.
- extras: PDAs, price/index hints useful for UIs and debugging.
- chainID: the chain the snapshot came from.Tranche snapshot fields (via
getTrancheSnapshot)
- currentTranche, currentPriceUsd (1e8), currentTrancheSupply, initialTrancheSupply.
- ladder: nearby rows { id, capacity, sold, remaining, priceUsd } (1e8 scale).
- currentIndex, totalShares, totalPretokensSold, supplyGrowthBps, priceGrowthCents.
- nativePriceUsd if available (SDK backfills from market data when the chain doesn’t provide it).Building, testing, docs
`bash
npm ci # install
npm run prepare # build to lib/ via rollup
npm test # full test suite (make targets exist for sol/eth split)
npm run docs # generate typedoc to docs/ (gh-pages ready)
`Project structure (src/)
- staker.ts – chain router / façade.
- types.ts – shared interfaces (IStakingClient, Portfolio, tranche snapshots).
- networks/solana/* – clients, IDL wiring, constants, utils.
- networks/ethereum/* – contract service, clients, tranche math.
- assets/ – IDLs, ABIs, artifacts.Versioning & license
- License: FSL-1.1-Apache-2.0 (see LICENSE.md`).