Skip to content

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.

Staking amounts are integer 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.
Last updated on