Skip to content

Commit fa28dde

Browse files
authored
feat: Babylon SDK Staking (#34)
* feat: baby staking * chore: getBabyStakingDelegations * chore: createWithdrawRewardForBTCStakingMsg * chore: createClaimRewardForBABYStakingMsg * chore: createStakeBABYMsg * chore: createUnstakeBABYMsg * chore: msg withdraw reward for btc staking * chore: msg stake baby * chore: msg unstake baby * chore: msg withdraw reward for baby staking * chore: claim -> withdraw
1 parent 91d7729 commit fa28dde

File tree

9 files changed

+416
-44
lines changed

9 files changed

+416
-44
lines changed

packages/babylon-proto-ts/README.md

Lines changed: 96 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,15 @@ const sdk = createBabylonSDK({ rpcUrl: "https://babylon-rpc.example.com" });
3131
// Connect the client
3232
await sdk.connect();
3333

34-
// Query rewards for an address
35-
const rewards = await sdk.client.getRewards("bbn1...");
34+
// Query BTC staking rewards for an address
35+
const btcRewards = await sdk.client.getRewardsForBTCStaking("bbn1...");
36+
37+
// Query BABY staking delegations and rewards
38+
const delegations = await sdk.client.getBabyStakingDelegations("bbn1...");
39+
const babyRewards = await sdk.client.getRewardsForBABYStaking("bbn1...");
40+
41+
// Get all validators
42+
const validators = await sdk.client.getValidators();
3643

3744
// Query balance
3845
const balance = await sdk.client.getBalance("bbn1...", "ubbn");
@@ -61,11 +68,22 @@ const client = await SigningStargateClient.connectWithSigner(
6168
},
6269
);
6370

64-
// Create messages using the SDK
65-
const withdrawMsg = sdk.messages.createWithdrawRewardMsg("bbn1...");
71+
// BTC Staking: Withdraw BTC staking rewards message
72+
const btcWithdrawMsg =
73+
sdk.messages.createWithdrawRewardForBTCStakingMsg("bbn1...");
74+
75+
// BABY Staking: Stake BABY tokens message
76+
const stakeMsg = sdk.messages.createStakeBABYMsg(
77+
"bbn1...", // delegator address
78+
"bbnvalidator...", // validator address
79+
{ denom: "ubbn", amount: "1000000" }, // 1 BBN
80+
);
6681

67-
// Sign and broadcast
68-
const result = await client.signAndBroadcast("bbn1...", [withdrawMsg], "auto");
82+
// BABY Staking: Withdraw BABY staking rewards message
83+
const withdrawMsg = sdk.messages.createWithdrawRewardForBABYStakingMsg(
84+
"bbn1...",
85+
"bbnvalidator...",
86+
);
6987
```
7088

7189
### Direct Protobuf Access
@@ -100,21 +118,21 @@ Initializes the client connection to the Babylon network.
100118

101119
### Client Methods (via sdk.client)
102120

103-
#### `sdk.client.getRewards(address: string): Promise<number>`
121+
#### `sdk.client.getRewardsForBTCStaking(address: string): Promise<number>`
104122

105-
Retrieves the total rewards for a given address.
123+
Retrieves the total BTC staking rewards for a given address.
106124

107125
- **Parameters:**
108126
- `address`: The Babylon address to query
109-
- **Returns:** Total rewards amount (number)
127+
- **Returns:** Total BTC staking rewards amount (number)
110128

111129
#### `sdk.client.getBalance(address: string, denom?: string): Promise<number>`
112130

113131
Gets the balance of a specific token for an address.
114132

115133
- **Parameters:**
116134
- `address`: The Babylon address to query
117-
- `denom`: Token denomination (defaults to "ubbn")
135+
- `denom`: Token denomination (defaults to `"ubbn"`)
118136
- **Returns:** Balance amount (number)
119137

120138
#### `sdk.client.getBTCTipHeight(): Promise<number>`
@@ -123,16 +141,67 @@ Retrieves the current Bitcoin blockchain tip height.
123141

124142
- **Returns:** Bitcoin tip height (number)
125143

144+
#### `sdk.client.getBabyStakingDelegations(address: string): Promise<DelegationResponse[]>`
145+
146+
Gets all BABY token delegations for a given address.
147+
148+
- **Parameters:**
149+
- `address`: The Babylon address to query
150+
- **Returns:** Array of delegation responses
151+
152+
#### `sdk.client.getRewardsForBABYStaking(address: string): Promise<DelegationDelegatorReward[]>`
153+
154+
Retrieves all BABY staking delegation rewards for a given address.
155+
156+
- **Parameters:**
157+
- `address`: The Babylon address to query
158+
- **Returns:** Array of delegation rewards
159+
160+
#### `sdk.client.getValidators(): Promise<Validator[]>`
161+
162+
Gets all validators in the network.
163+
164+
- **Returns:** Array of all validators
165+
126166
### SDK Messages
127167

128-
#### `sdk.messages.createWithdrawRewardMsg(address: string)`
168+
#### `sdk.messages.createWithdrawRewardForBTCStakingMsg(address: string)`
129169

130170
Creates a message for withdrawing rewards from Bitcoin staking.
131171

132172
- **Parameters:**
133173
- `address`: The Babylon address to withdraw rewards for
134174
- **Returns:** Message object with proper typeUrl and value, ready for signing and broadcasting
135175

176+
#### `sdk.messages.createStakeBABYMsg(delegatorAddress: string, validatorAddress: string, amount: Coin)`
177+
178+
Creates a message for staking BABY tokens.
179+
180+
- **Parameters:**
181+
- `delegatorAddress`: The delegator's Babylon address
182+
- `validatorAddress`: The validator's Babylon address
183+
- `amount`: The amount to stake (Coin object with amount and denom)
184+
- **Returns:** Message object with proper typeUrl and value, ready for signing and broadcasting
185+
186+
#### `sdk.messages.createUnstakeBABYMsg(delegatorAddress: string, validatorAddress: string, amount: Coin)`
187+
188+
Creates a message for unstaking BABY tokens.
189+
190+
- **Parameters:**
191+
- `delegatorAddress`: The delegator's Babylon address
192+
- `validatorAddress`: The validator's Babylon address
193+
- `amount`: The amount to unstake (Coin object with amount and denom)
194+
- **Returns:** Message object with proper typeUrl and value, ready for signing and broadcasting
195+
196+
#### `sdk.messages.createWithdrawRewardForBABYStakingMsg(delegatorAddress: string, validatorAddress: string)`
197+
198+
Creates a message for withdrawing BABY staking rewards.
199+
200+
- **Parameters:**
201+
- `delegatorAddress`: The delegator's Babylon address
202+
- `validatorAddress`: The validator's Babylon address
203+
- **Returns:** Message object with proper typeUrl and value, ready for signing and broadcasting
204+
136205
### SDK Utilities
137206

138207
#### `sdk.utils.createRegistry(): Registry`
@@ -143,6 +212,22 @@ Creates a CosmJS registry with all Babylon message types registered.
143212

144213
Creates amino types for Babylon messages, required for hardware wallet compatibility.
145214

215+
#### `sdk.utils.normalizeCosmjsAmount(amount: string): string`
216+
217+
Normalizes CosmJS amount from 18-decimal precision to standard `ubbn` format.
218+
219+
- **Parameters:**
220+
- `amount`: The amount string from CosmJS (with 18 decimal precision)
221+
- **Returns:** The normalized amount as a string in standard `ubbn` format
222+
223+
#### `sdk.utils.normalizeRewardResponse(response: QueryDelegationTotalRewardsResponse)`
224+
225+
Normalizes reward response from CosmJS to standard `ubbn` format.
226+
227+
- **Parameters:**
228+
- `response`: The QueryDelegationTotalRewardsResponse from CosmJS
229+
- **Returns:** The normalized reward array with amounts in standard `ubbn` format
230+
146231
### Protobuf Exports
147232

148233
The library exports all generated protobuf types directly, allowing for advanced use cases

packages/babylon-proto-ts/src/constants.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,9 @@ export const REWARD_GAUGE_KEY_BTC_DELEGATION = "BTC_STAKER";
22
export const BTC_STAKER = "btc_staker";
33
export const REGISTRY_TYPE_URLS = {
44
MsgCreateBTCDelegation: "/babylon.btcstaking.v1.MsgCreateBTCDelegation",
5-
MsgWithdrawReward: "/babylon.incentive.MsgWithdrawReward",
5+
MsgWithdrawRewardForBTCStaking: "/babylon.incentive.MsgWithdrawReward",
6+
MsgStakeBABY: "/babylon.epoching.v1.MsgWrappedDelegate",
7+
MsgUnstakeBABY: "/babylon.epoching.v1.MsgWrappedUndelegate",
8+
MsgWithdrawRewardForBABYStaking:
9+
"/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward",
610
};

packages/babylon-proto-ts/src/lib/client.ts

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
import {
22
BankExtension,
33
Coin,
4+
DistributionExtension,
45
QueryClient,
6+
StakingExtension,
57
createProtobufRpcClient,
68
setupBankExtension,
9+
setupDistributionExtension,
10+
setupStakingExtension,
711
} from "@cosmjs/stargate";
812
import { Tendermint34Client } from "@cosmjs/tendermint-rpc";
13+
import { DelegationDelegatorReward } from "cosmjs-types/cosmos/distribution/v1beta1/distribution";
14+
import {
15+
DelegationResponse,
16+
Validator,
17+
} from "cosmjs-types/cosmos/staking/v1beta1/staking";
918

1019
import { REWARD_GAUGE_KEY_BTC_DELEGATION } from "../constants";
1120
import * as btclightclientquery from "../generated/babylon/btclightclient/v1/query";
1221
import * as incentivequery from "../generated/babylon/incentive/query";
1322

1423
interface Clients {
15-
incentive: incentivequery.QueryClientImpl;
16-
btcLight: btclightclientquery.QueryClientImpl;
17-
bank: BankExtension["bank"];
24+
incentive: incentivequery.QueryClientImpl | null;
25+
btcLight: btclightclientquery.QueryClientImpl | null;
26+
bank: BankExtension["bank"] | null;
27+
staking: StakingExtension["staking"] | null;
28+
distribution: DistributionExtension["distribution"] | null;
1829
}
1930

2031
type ClientNames = keyof Clients;
@@ -26,13 +37,17 @@ export class BabylonClient {
2637
incentive: null,
2738
btcLight: null,
2839
bank: null,
40+
staking: null,
41+
distribution: null,
2942
};
3043

3144
constructor(rpcUrl: string) {
3245
this.rpcUrl = rpcUrl;
3346
}
3447

35-
private getClient<K extends ClientNames>(clientName: K): Clients[K] {
48+
private getClient<K extends ClientNames>(
49+
clientName: K,
50+
): NonNullable<Clients[K]> {
3651
if (!this.clients[clientName]) {
3752
throw Error("Babylon Client not initialized");
3853
}
@@ -45,20 +60,25 @@ export class BabylonClient {
4560
const queryClient = QueryClient.withExtensions(
4661
tmClient,
4762
setupBankExtension,
63+
setupStakingExtension,
64+
setupDistributionExtension,
4865
);
4966
const rpc = createProtobufRpcClient(queryClient);
5067

5168
this.clients.incentive = new incentivequery.QueryClientImpl(rpc);
5269
this.clients.btcLight = new btclightclientquery.QueryClientImpl(rpc);
5370
this.clients.bank = setupBankExtension(queryClient).bank;
71+
this.clients.staking = setupStakingExtension(queryClient).staking;
72+
this.clients.distribution =
73+
setupDistributionExtension(queryClient).distribution;
5474
}
5575

5676
/**
57-
* Gets the rewards of an address in the Babylon chain.
77+
* [BTC Staking] Gets the rewards of the user's account.
5878
* @param {string} address - The address to get the rewards of.
5979
* @returns {Promise<number>} - The rewards of the address.
6080
*/
61-
async getRewards(address: string): Promise<number> {
81+
async getRewardsForBTCStaking(address: string): Promise<number> {
6282
try {
6383
const req = incentivequery.QueryRewardGaugesRequest.fromPartial({
6484
address,
@@ -137,6 +157,62 @@ export class BabylonClient {
137157
});
138158
}
139159
}
160+
161+
/**
162+
* [BABY Staking] Gets all delegations of the user's account.
163+
* @param {string} address - The address to get the delegations of.
164+
* @returns {Promise<DelegationResponse[]>} - The delegations of the address.
165+
*/
166+
async getBabyStakingDelegations(
167+
address: string,
168+
): Promise<DelegationResponse[]> {
169+
try {
170+
const response =
171+
await this.getClient("staking").delegatorDelegations(address);
172+
return response.delegationResponses || [];
173+
} catch (error) {
174+
throw new Error(`Failed to fetch delegations for ${address}`, {
175+
cause: error,
176+
});
177+
}
178+
}
179+
180+
/**
181+
* [BABY Staking] Gets all delegation rewards of the user's account.
182+
* @param {string} address - The address to get the delegation rewards of.
183+
* @returns {Promise<DelegationDelegatorReward[]>} - The delegation rewards of the address.
184+
*/
185+
async getRewardsForBABYStaking(
186+
address: string,
187+
): Promise<DelegationDelegatorReward[]> {
188+
try {
189+
const response =
190+
await this.getClient("distribution").delegationTotalRewards(address);
191+
return response.rewards || [];
192+
} catch (error) {
193+
if (error instanceof Error && error.message.includes("no delegation")) {
194+
return [];
195+
}
196+
throw new Error(`Failed to fetch delegation rewards for ${address}`, {
197+
cause: error,
198+
});
199+
}
200+
}
201+
202+
/**
203+
* [BABY Staking] Gets all the validators.
204+
* @returns {Promise<Validator[]>} - All validators.
205+
*/
206+
async getValidators(): Promise<Validator[]> {
207+
try {
208+
const response = await this.getClient("staking").validators("");
209+
return response.validators || [];
210+
} catch (error) {
211+
throw new Error(`Failed to fetch validators`, {
212+
cause: error,
213+
});
214+
}
215+
}
140216
}
141217

142218
export const createBabylonClient = (rpcUrl: string) =>

0 commit comments

Comments
 (0)