Staking
HYPE staking happens on HyperCore: move HYPE from spot into your staking
balance, delegate it to validators, and move it back when you are done.
Staking actions are user-signed, so the client must sign with the account’s
own key, not an API wallet. The one exception is
AgentCDeposit, an L1
version of CDeposit that an API wallet may sign.
Wei fields in units of 10⁻⁸ HYPE:
100_000_000 is 1 HYPE. Info results report amounts as decimal HYPE
strings, except ValidatorSummary.Stake, which is in the same wei.Stake and delegate
const hype = 100_000_000 // 1 HYPE in wei
// Spot -> staking balance.
err := ex.CDeposit(ctx, hyperliquid.CDepositAction{Wei: 10 * hype})
if err != nil {
log.Fatal(err)
}
// Delegate to a validator.
err = ex.TokenDelegate(ctx, hyperliquid.TokenDelegateAction{
Validator: validator,
Wei: 10 * hype,
})
if err != nil {
log.Fatal(err)
}CDeposit is
instant. Pick a validator from
ValidatorSummaries:
validators, err := info.ValidatorSummaries(ctx)
if err != nil {
log.Fatal(err)
}
for _, v := range validators {
if v.IsActive && !v.IsJailed {
fmt.Println(v.Name, v.Validator, "commission", v.Commission)
}
}Undelegate and unstake
// Undelegate back to the staking balance.
err := ex.TokenDelegate(ctx, hyperliquid.TokenDelegateAction{
Validator: validator,
Wei: 5 * hype,
IsUndelegate: true,
})
if err != nil {
log.Fatal(err)
}
// Staking balance -> spot, through the unstaking queue.
err = ex.CWithdraw(ctx, hyperliquid.CWithdrawAction{Wei: 5 * hype})
if err != nil {
log.Fatal(err)
}Per the Hyperliquid staking docs:
a delegation is locked for one day, CWithdraw
only moves undelegated HYPE and finalizes after a 7-day queue, and an
address can have at most 5 pending withdrawals. Rewards are redelegated to
the validator automatically; there is no claim step.
(ClaimRewards
claims referral and builder rewards, not staking rewards.)
Read staking state
summary, err := info.DelegatorSummary(ctx, hyperliquid.DelegatorSummaryRequest{User: user})
if err != nil {
log.Fatal(err)
}
fmt.Println("delegated", summary.Delegated, "undelegated", summary.Undelegated,
"pending withdrawal", summary.TotalPendingWithdrawal)
delegations, err := info.Delegations(ctx, hyperliquid.DelegationsRequest{User: user})
if err != nil {
log.Fatal(err)
}
for _, d := range delegations {
fmt.Println(d.Validator, d.Amount, "locked until", time.UnixMilli(d.LockedUntilTimestamp))
}
rewards, err := info.DelegatorRewards(ctx, hyperliquid.DelegatorRewardsRequest{User: user})
if err != nil {
log.Fatal(err)
}
for _, r := range rewards {
fmt.Println(time.UnixMilli(r.Time), r.Source, r.TotalAmount)
}DelegatorHistory
lists every deposit, delegation and withdrawal. Each event’s Delta has
exactly one field set:
history, err := info.DelegatorHistory(ctx, hyperliquid.DelegatorHistoryRequest{User: user})
if err != nil {
log.Fatal(err)
}
for _, e := range history {
switch d := e.Delta; {
case d.Delegate != nil:
fmt.Println("delegate", d.Delegate.Validator, d.Delegate.Amount, "undelegate:", d.Delegate.IsUndelegate)
case d.CDeposit != nil:
fmt.Println("deposit", d.CDeposit.Amount)
case d.Withdrawal != nil:
fmt.Println("withdrawal", d.Withdrawal.Amount, d.Withdrawal.Phase)
}
}Link a trading account to a staking account
LinkStakingUser
gives a trading account the fee discount of a separate staking account. It
takes two actions, each signed by its own account’s key: the trading
account requests the link, then the staking account finalizes it.
// Signed by the trading account.
err := tradingEx.LinkStakingUser(ctx, hyperliquid.LinkStakingUserAction{User: stakingUser})
if err != nil {
log.Fatal(err)
}
// Signed by the staking account.
err = stakingEx.LinkStakingUser(ctx, hyperliquid.LinkStakingUserAction{
User: tradingUser,
IsFinalize: true,
})
if err != nil {
log.Fatal(err)
}InfoClient.UserFees reports the link in StakingLink.
StakingLinkDisableTradingUser
permanently disables a linked trading account and locks its funds, which
move to the staking account after one year. It cannot be undone.