@wireio/stake
v2.3.1
Published
LIQ Staking Module for Wire Network
Readme
@wireio/stake — Outpost & LIQ Staking SDK
TypeScript / 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.).
What this SDK does
- One
Stakerthat selects the right chain client bychainId. - Deposit / withdraw native → LIQ tokens (SOL→liqSOL, ETH→liqETH).
- Stake / unstake LIQ into yield pools (Solana Outpost; Ethereum staking manager).
- Pre-launch WIRE pretokens purchase helpers.
- Rich
getPortfolioview (native, liq, staked, $WIRE, yield, extras). - Gas / fee helpers (
getDepositFee,getDepositBuffer,getSystemAPY). - Solana extras: balance correction + registration, Outpost state, multisig (SquadsX) flows.
- Ethereum extras: withdrawal receipts, validator deposit/lock, tranche snapshots.
SquadsX (Solana multisig) at a glance
- Pass
extras.squadsXwhen constructing a SolanaStakerConfig:const cfg: StakerConfig = { provider: solAdapter, network: solNetwork, pubKey: new WirePubKey(KeyType.ED, solAdapter.publicKey!.toBytes()), extras: { squadsX: { multisigPDA: '<base58>', vaultIndex: 0 } }, }; - When present, every write call (
deposit,withdraw,stake,unstake,buy) is wrapped as a Squads vault transaction viasendSquadsIxs, 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 theStakerwith Squads enabled; copy that pattern for multisig-first apps.
Mental model
- Facade first: Use
Stakereverywhere; 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
npm install @wireio/stakePeer requirement: @wireio/core >=0.1.0 <0.4.0.
Quick start: pick a chain, then call through client
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: '<base58>', 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 chainCommon calls
Amounts are always base units (lamports / wei).
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 snapshotSolana flow (what happens)
deposit(lamports): builds ix viaDepositClient, 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.squadsXis set, write calls become Squads proposals (sendSquadsIxs). - Portfolio extras include key PDAs (vault, reserve pool, user ATA) plus Outpost index/shares math.
Ethereum flow (what happens)
deposit(amountWei): viaConvertClient.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 viaPretokenClient.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.squadsXto have deposits / stakes wrapped as vault transactions (sendSquadsIxs). - Outpost / Yield:
getPortfolio()returnsyield(index-scale math) andstakedamounts;wirereports pretokens (1e8 scale). - Helpers:
getDepositBuffer,getDepositFee,getSystemAPY, tranche snapshots viagetTrancheSnapshot(chainId).
Ethereum specifics
- Uses
ethersprovider/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?)andgetEthStats()for operator/pay-rate data.
Portfolio shape (all chains)
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<string, any>;
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
provideris 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:
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
networkto 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 keyshub_squadsx_multisigpda,hub_squadsx_vaultindex) and pass viaextras.squadsXso 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.nativePriceUsdif available (SDK backfills from market data when the chain doesn’t provide it).
Building, testing, docs
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).
Links
- API reference: https://Wire-Network.github.io/sdk-stake/
- Source: https://github.com/Wire-Network/sdk-stake
