Monad
@stakefish/sdk-monad
The @stakefish/sdk-monad is a JavaScript/TypeScript library that provides a unified interface for staking operations on the Monad blockchain with stake.fish validators. It allows developers to easily delegate stakes, undelegate, withdraw, claim rewards, compound 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-monadyarn add @stakefish/sdk-monadAPI Reference
Constructor
interface MonadConfig {
rpcUrl: string;
}
export class Monad {
constructor(config: MonadConfig)
// ...
}rpcUrl(required): Monad RPC endpoint URL for transaction broadcasting
Note: The SDK is hardcoded to use the stake.fish validator (ID: 152, Address: 0x606052370B215b346864724F10723dBd5e1423e8). All staking operations will be directed to this validator.
Delegation
delegate(params: { delegatorAddress: string; amount: string }): Promise<MonadUnsignedTransaction>Creates an unsigned transaction for delegating a specified amount of MON tokens (in wei, the smallest unit) from the delegator's address to the stake.fish validator.
Parameters:
params.delegatorAddress: The Monad address of the delegator (e.g., '0x...')params.amount: The amount to delegate in wei (1 MON = 10^18 wei)
Minimum Delegation: 0.1 MON (100000000000000000 wei)
Reserve Balance: You must maintain at least 10 MON in your wallet for gas fees
Undelegation
undelegate(params: { delegatorAddress: string; amount: string; withdrawId?: string }): Promise<MonadUnsignedTransaction>Creates an unsigned transaction for undelegating a specified amount from the stake.fish validator. This starts the unbonding period before you can withdraw the tokens.
Parameters:
params.delegatorAddress: The Monad address of the delegatorparams.amount: The amount to undelegate in weiparams.withdrawId(optional): Withdrawal identifier (0-255), defaults to '0'. Each (validator, delegator) pair can have up to 256 in-flight withdrawal requests.
Withdraw
withdraw(params: { delegatorAddress: string; withdrawId: string }): Promise<MonadUnsignedTransaction>Creates an unsigned transaction for withdrawing previously undelegated tokens after the unbonding period has completed.
Parameters:
params.delegatorAddress: The Monad address of the delegatorparams.withdrawId: The withdrawal identifier (must match the ID used in undelegate)
Claim Rewards
claimRewards(delegatorAddress: string): Promise<MonadUnsignedTransaction>Creates an unsigned transaction for claiming MON staking rewards from the stake.fish validator.
Parameters:
delegatorAddress: The Monad address of the delegator
Compound
compound(delegatorAddress: string): Promise<MonadUnsignedTransaction>Creates an unsigned transaction for compounding (restaking) MON staking rewards back into delegation.
Parameters:
delegatorAddress: The Monad address of the delegator
Get Balance
getBalance(address: string): Promise<string>Gets the native MON balance for a given address.
Parameters:
address: The Monad address to check balance for
Returns: MON balance in wei as a string
Signing
sign(privateKeyHex: string, unsignedTx: MonadUnsignedTransaction): Promise<MonadSignedTransaction>Signs an unsigned transaction using a private key. This can be done offline.
Parameters:
privateKeyHex: The private key in hexadecimal format (with or without '0x' prefix)unsignedTx: The unsigned transaction returned from prepare methods
Returns: A signed transaction object
Broadcasting
broadcast(
signedTx: MonadSignedTransaction,
checkInclusion?: boolean,
timeoutMs?: number,
pollIntervalMs?: number
): Promise<MonadTransactionBroadcastResult>Broadcasts a signed transaction to the Monad network.
Parameters:
signedTx: The signed transaction from sign()checkInclusion(optional): Whether to wait for transaction inclusion (default: false)timeoutMs(optional): Timeout in milliseconds (default: 60000)pollIntervalMs(optional): Polling interval in milliseconds (default: 1000)
Returns: Transaction broadcast result with transaction hash
Examples
Complete Delegation Flow
import { Monad } from '@stakefish/sdk-monad';
// Initialize SDK
const monad = new Monad({
rpcUrl: 'https://monad-rpc-url',
});
async function delegateExample() {
// 1. Check balance
const address = '0xCEB64AcfB2d993A9689B454AB3039AE155d6b607';
const balance = await monad.getBalance(address);
console.log('Balance:', balance, 'wei');
// 2. Prepare delegation transaction (delegate 1 MON)
const unsignedTx = await monad.delegate({
delegatorAddress: address,
amount: '1000000000000000000', // 1 MON in wei
});
// 3. Sign transaction offline
const privateKey = 'your-private-key-here';
const signedTx = await monad.sign(privateKey, unsignedTx);
// 4. Broadcast transaction
const result = await monad.broadcast(signedTx, true); // Wait for inclusion
console.log('Transaction hash:', result.txId);
console.log('Status:', result.status);
}Undelegation and Withdrawal Flow
import { Monad } from '@stakefish/sdk-monad';
const monad = new Monad({
rpcUrl: 'https://monad-rpc-url',
});
async function undelegateExample() {
const address = '0xCEB64AcfB2d993A9689B454AB3039AE155d6b607';
const privateKey = 'your-private-key-here';
const withdrawId = '0'; // Use same ID for undelegate and withdraw
// 1. Undelegate 0.5 MON
const undelegateTx = await monad.undelegate({
delegatorAddress: address,
amount: '500000000000000000', // 0.5 MON
withdrawId: withdrawId,
});
const signedUndelegate = await monad.sign(privateKey, undelegateTx);
const undelegateResult = await monad.broadcast(signedUndelegate, true);
console.log('Undelegation tx:', undelegateResult.txId);
// 2. Wait for unbonding period to complete (varies by network)
// ...
// 3. Withdraw undelegated tokens
const withdrawTx = await monad.withdraw({
delegatorAddress: address,
withdrawId: withdrawId, // Must match the ID used in undelegate
});
const signedWithdraw = await monad.sign(privateKey, withdrawTx);
const withdrawResult = await monad.broadcast(signedWithdraw, true);
console.log('Withdrawal tx:', withdrawResult.txId);
}Compound Rewards
import { Monad } from '@stakefish/sdk-monad';
const monad = new Monad({
rpcUrl: 'https://monad-rpc-url',
});
async function compoundExample() {
const address = '0xCEB64AcfB2d993A9689B454AB3039AE155d6b607';
const privateKey = 'your-private-key-here';
// Compound rewards back into delegation
const compoundTx = await monad.compound(address);
const signedTx = await monad.sign(privateKey, compoundTx);
const result = await monad.broadcast(signedTx, true);
console.log('Compound tx:', result.txId);
}Notes
Important Constraints
- Minimum Delegation: 0.1 MON (100000000000000000 wei)
- Reserve Balance: Must maintain at least 10 MON in wallet for gas fees
- WithdrawId Range: 0-255 (each validator-delegator pair supports up to 256 concurrent withdrawal requests)
- Amount Format: All amounts must be in wei (1 MON = 10^18 wei) as positive integer strings
Native Token
Monad uses the native MON token for staking. Unlike ERC20 tokens, you do NOT need to approve the StakeManager contract before delegating.
Gas Fees
All transactions require MON for gas fees. Ensure your wallet has sufficient balance beyond your delegation amount to cover gas costs.
Withdrawal Process
- Call
undelegate()with awithdrawId(0-255) - Wait for the unbonding period to complete
- Call
withdraw()with the samewithdrawIdto claim your tokens
Error Handling
The SDK will throw errors for:
- Invalid addresses (must be 0x followed by 40 hex characters)
- Invalid amounts (must be positive integer strings)
- Amounts below minimum delegation (0.1 MON)
- Insufficient balance (including reserve requirement)
- Invalid withdrawId (must be 0-255)
Updated 3 days ago
