Polygon

@stakefish/sdk-polygon

The @stakefish/sdk-polygon is a JavaScript/TypeScript library that provides a unified interface for staking operations on the Polygon PoS blockchain with stake.fish validators. It allows developers to easily delegate stakes, undelegate, claim rewards, sign transactions, and broadcast them to the network.

Table of Contents

Installation

To use this SDK in your project, install it via npm or yarn:

npm install @stakefish/sdk-polygon
yarn add @stakefish/sdk-polygon

Type Imports

import { Polygon } from '@stakefish/sdk-polygon';
import type {
  PolygonConfig,
  PolygonPrepareDelegate,
  PolygonPrepareUndelegate,
  PolygonPrepareClaimRewards,
  PolygonPrepareClaimUnstaked,
  PolygonPrepareRestakeRewards,
  PolygonPrepareApprove,
  PolygonGetBalance,
  PolygonGetAllowance,
  PolygonSign,
  PolygonBroadcast,
  PolygonUnsignedTransaction,
  PolygonSignedTransaction,
  PolygonTransactionBroadcastResult,
} from '@stakefish/sdk-polygon';

API Reference

Constructor

import type { PolygonConfig } from '@stakefish/sdk-polygon';

new Polygon({ ethereumRpcUrl: 'https://mainnet.infura.io/v3/YOUR_PROJECT_ID' }: PolygonConfig)

Creates a new Polygon SDK instance.

Parameters:

  • ethereumRpcUrl: Ethereum RPC endpoint URL for transaction broadcasting

delegate

import type { PolygonPrepareDelegate, PolygonUnsignedTransaction } from '@stakefish/sdk-polygon';

delegate({ delegatorAddress: '0x...', amount: '1000000000000000000', token: 'POL' }: PolygonPrepareDelegate): Promise<PolygonUnsignedTransaction>

Creates an unsigned transaction for delegating a specified amount of POL or MATIC tokens (in wei, the smallest unit) from the delegator's address to the stake.fish validator.

Parameters:

  • delegatorAddress: The Ethereum address of the delegator (e.g., 0x...)
  • amount: The amount to delegate in wei (1 POL = 10^18 wei, 1 MATIC = 10^18 wei)
  • token (optional): Token to delegate ('POL' or 'MATIC'), defaults to 'POL'

undelegate

import type { PolygonPrepareUndelegate, PolygonUnsignedTransaction } from '@stakefish/sdk-polygon';

undelegate({ delegatorAddress: '0x...', amount: '1000000000000000000' }: PolygonPrepareUndelegate): Promise<PolygonUnsignedTransaction>

Creates an unsigned transaction for undelegating a specified amount from the stake.fish validator. This starts a 3-4 day unbonding period.

Parameters:

  • delegatorAddress: The Ethereum address of the delegator
  • amount: The amount to undelegate in wei (1 POL = 10^18 wei)

claimRewards

import type { PolygonPrepareClaimRewards, PolygonUnsignedTransaction } from '@stakefish/sdk-polygon';

claimRewards({ delegatorAddress: '0x...' }: PolygonPrepareClaimRewards): Promise<PolygonUnsignedTransaction>

Creates an unsigned transaction for claiming POL staking rewards from the stake.fish validator.

Parameters:

  • delegatorAddress: The Ethereum address of the delegator

claimUnstaked

import type { PolygonPrepareClaimUnstaked, PolygonUnsignedTransaction } from '@stakefish/sdk-polygon';

claimUnstaked({ delegatorAddress: '0x...', unbondNonce: '12345' }: PolygonPrepareClaimUnstaked): Promise<PolygonUnsignedTransaction>

Creates an unsigned transaction for claiming unstaked tokens after the unbonding period has completed.

Parameters:

  • delegatorAddress: The Ethereum address of the delegator
  • unbondNonce: The nonce from the undelegation transaction

restakeRewards

import type { PolygonPrepareRestakeRewards, PolygonUnsignedTransaction } from '@stakefish/sdk-polygon';

restakeRewards({ delegatorAddress: '0x...' }: PolygonPrepareRestakeRewards): Promise<PolygonUnsignedTransaction>

Creates an unsigned transaction for compounding POL staking rewards into delegation.

Parameters:

  • delegatorAddress: The Ethereum address of the delegator

approve

import type { PolygonPrepareApprove, PolygonUnsignedTransaction } from '@stakefish/sdk-polygon';

approve({ delegatorAddress: '0x...', amount: '1000000000000000000', token: 'POL' }: PolygonPrepareApprove): Promise<PolygonUnsignedTransaction>

Creates an unsigned transaction to approve the StakeManager contract to spend tokens on behalf of the delegator. Important: Approval must be given to the StakeManager contract, NOT the ValidatorShare contract.

Parameters:

  • delegatorAddress: The Ethereum address of the delegator
  • amount: The amount to approve in wei
  • token (optional): Token to approve ('POL' or 'MATIC'), defaults to 'POL'

getBalance

import type { PolygonGetBalance } from '@stakefish/sdk-polygon';

getBalance({ delegatorAddress: '0x...', token: 'POL' }: PolygonGetBalance): Promise<string>

Gets the token balance for a given address.

Parameters:

  • delegatorAddress: The Ethereum address to check balance for
  • token (optional): Token to check balance for ('POL' or 'MATIC'), defaults to 'POL'

getAllowance

import type { PolygonGetAllowance } from '@stakefish/sdk-polygon';

getAllowance({ delegatorAddress: '0x...', token: 'POL' }: PolygonGetAllowance): Promise<string>

Gets the amount of tokens that the StakeManager contract is approved to spend on behalf of the delegator.

Parameters:

  • delegatorAddress: The Ethereum address of the delegator
  • token (optional): Token to check allowance for ('POL' or 'MATIC'), defaults to 'POL'

sign

import type { PolygonSign, PolygonSignedTransaction, PolygonUnsignedTransaction } from '@stakefish/sdk-polygon';

sign({ privateKeyHex: '0x...', unsignedTx }: PolygonSign): Promise<PolygonSignedTransaction>

Signs the unsigned transaction using the provided private key. This operation works completely offline and does not require network connectivity.

Parameters:

  • privateKeyHex: The private key in hexadecimal format (with or without '0x' prefix)
  • unsignedTx: The unsigned transaction object from delegate(), undelegate(), claimRewards(), claimUnstaked(), or restakeRewards()

broadcast

import type { PolygonBroadcast, PolygonTransactionBroadcastResult, PolygonSignedTransaction } from '@stakefish/sdk-polygon';

broadcast({ signedTx, checkInclusion: false, timeoutMs: 60000, pollIntervalMs: 2000 }: PolygonBroadcast): Promise<PolygonTransactionBroadcastResult>

Broadcasts the signed transaction to the Ethereum network and optionally waits for inclusion confirmation.

Parameters:

  • signedTx: The signed transaction object from sign()
  • checkInclusion (optional): Whether to wait for transaction inclusion (default: false)
  • timeoutMs (optional): Maximum time to wait for inclusion in milliseconds (default: 60000)
  • pollIntervalMs (optional): Interval between inclusion checks in milliseconds (default: 2000)

Returns: PolygonTransactionBroadcastResult object containing:

  • txId: The transaction hash
  • success: Boolean indicating if the transaction was successful
  • error: Error message if the transaction failed (optional)

Examples

Full delegation example

import { Polygon } from '@stakefish/sdk-polygon';
import type {
  PolygonConfig,
  PolygonUnsignedTransaction,
  PolygonSignedTransaction,
  PolygonTransactionBroadcastResult,
} from '@stakefish/sdk-polygon';
// or: const { Polygon } = require('@stakefish/sdk-polygon');

const delegator = process.env.ETHEREUM_ADDRESS;
const rpcUrl = process.env.ETHEREUM_RPC_URL;
const privateKeyHex = process.env.ETHEREUM_PRIVATE_KEY;

async function main() {
  const polygon = new Polygon({
    ethereumRpcUrl: rpcUrl,
  });

  // Delegation (1 POL = 10^18 wei)
  const unsignedTx: PolygonUnsignedTransaction = await polygon.delegate({
    delegatorAddress: delegator,
    amount: '1000000000000000000',
  });

  // Sign
  const signedTx: PolygonSignedTransaction = await polygon.sign({ privateKeyHex, unsignedTx });

  // Broadcast
  const result: PolygonTransactionBroadcastResult = await polygon.broadcast({ signedTx });
  console.log('Broadcast result:', JSON.stringify(result));
}

void main().catch(console.error);

MATIC Delegation

// Delegation with MATIC tokens (1 MATIC = 10^18 wei)
const unsignedTx: PolygonUnsignedTransaction = await polygon.delegate({
  delegatorAddress: delegator,
  amount: '1000000000000000000',
  token: 'MATIC',
});

Undelegation

const unsignedTx: PolygonUnsignedTransaction = await polygon.undelegate({
  delegatorAddress: delegator,
  amount: '1000000000000000000',
});

Claim Rewards

const unsignedTx: PolygonUnsignedTransaction = await polygon.claimRewards({
  delegatorAddress: delegator,
});

Claim Unstaked

const unsignedTx: PolygonUnsignedTransaction = await polygon.claimUnstaked({
  delegatorAddress: delegator,
  unbondNonce: '12345',
});

Restake Rewards

const unsignedTx: PolygonUnsignedTransaction = await polygon.restakeRewards({
  delegatorAddress: delegator,
});

Approve POL Tokens

// Approve StakeManager contract to spend 1 POL
const unsignedTx: PolygonUnsignedTransaction = await polygon.approve({
  delegatorAddress: delegator,
  amount: '1000000000000000000',
  token: 'POL',
});

Approve MATIC Tokens

// Approve StakeManager contract to spend 1 MATIC
const unsignedTx: PolygonUnsignedTransaction = await polygon.approve({
  delegatorAddress: delegator,
  amount: '1000000000000000000',
  token: 'MATIC',
});

Check POL Balance

const balance: string = await polygon.getBalance({
  delegatorAddress: delegator,
  token: 'POL',
});
console.log(`POL Balance: ${balance} wei`);

Check MATIC Balance

const balance: string = await polygon.getBalance({
  delegatorAddress: delegator,
  token: 'MATIC',
});
console.log(`MATIC Balance: ${balance} wei`);

Check POL Allowance

const allowance: string = await polygon.getAllowance({
  delegatorAddress: delegator,
  token: 'POL',
});
console.log(`POL Allowance: ${allowance} wei`);

Check MATIC Allowance

const allowance: string = await polygon.getAllowance({
  delegatorAddress: delegator,
  token: 'MATIC',
});
console.log(`MATIC Allowance: ${allowance} wei`);

Configuration

The SDK requires configuration during instantiation with Ethereum RPC endpoint:

import type { PolygonConfig } from '@stakefish/sdk-polygon';

const polygon = new Polygon({
  ethereumRpcUrl: 'https://mainnet.infura.io/v3/YOUR_PROJECT_ID',
} as PolygonConfig);

Notes

  • Staking happens on Ethereum mainnet, not on Polygon chain
  • You need ETH to pay gas fees for staking transactions
  • POL tokens must be on Ethereum mainnet to stake
  • Use Polygon Portal to bridge POL from Polygon to Ethereum if needed
  • All amounts in the SDK are specified in wei, the smallest unit of POL (1 POL = 10^18 wei)
  • The SDK automatically handles gas estimation and fee calculation for transactions
  • Private keys can be provided in hexadecimal format with or without the '0x' prefix
  • Private keys should be kept secure and never committed to version control