Skip to content

Commit 4e59dc6

Browse files
committed
feat(sdk-coin-baby): add sdk support for babylon native staking
TICKET: SC-1276
1 parent c5f1072 commit 4e59dc6

14 files changed

+743
-31
lines changed

modules/abstract-cosmos/src/lib/utils.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,15 @@ export class CosmosUtils implements BaseUtils {
369369
return encodePubkey(encodeSecp256k1Pubkey(fromHex(pubkey)));
370370
}
371371

372+
/**
373+
* Gets the send messages used in the final step of encoding a transaction. This allows for any final processing needed.
374+
* @param {CosmosLikeTransaction} cosmosLikeTransaction transaction to get send messages from
375+
* @returns {Any[]} processed send messages
376+
*/
377+
getSendMessagesForEncodingTx(cosmosLikeTransaction: CosmosLikeTransaction): Any[] {
378+
return cosmosLikeTransaction.sendMessages as unknown as Any[];
379+
}
380+
372381
/**
373382
* Creates a txRaw from an cosmos like transaction @see CosmosLikeTransaction
374383
* @Precondition cosmosLikeTransaction.publicKey must be defined
@@ -380,7 +389,7 @@ export class CosmosUtils implements BaseUtils {
380389
throw new Error('publicKey is required to create a txRaw');
381390
}
382391
const encodedPublicKey: Any = this.getEncodedPubkey(cosmosLikeTransaction.publicKey);
383-
const messages = cosmosLikeTransaction.sendMessages as unknown as Any[];
392+
const messages = this.getSendMessagesForEncodingTx(cosmosLikeTransaction);
384393
let txBodyValue;
385394
if (cosmosLikeTransaction.memo) {
386395
txBodyValue = {

modules/sdk-coin-baby/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,13 @@
4343
"@bitgo/abstract-cosmos": "^11.5.1",
4444
"@bitgo/sdk-core": "^31.1.0",
4545
"@bitgo/statics": "^51.3.0",
46+
"@babylonlabs-io/babylon-proto-ts": "1.0.0",
4647
"@cosmjs/amino": "^0.29.5",
4748
"@cosmjs/encoding": "^0.29.5",
49+
"@cosmjs/proto-signing": "^0.29.5",
4850
"@cosmjs/stargate": "^0.29.5",
49-
"bignumber.js": "^9.1.1"
51+
"bignumber.js": "^9.1.1",
52+
"cosmjs-types": "^0.6.1"
5053
},
5154
"devDependencies": {
5255
"@bitgo/sdk-api": "^1.61.0",
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as constants from './constants';
2+
import { StakingActivateBuilder } from '@bitgo/abstract-cosmos';
3+
4+
export class EpochedStakingActivateBuilder extends StakingActivateBuilder {
5+
/** @inheritdoc */
6+
messages(delegateMessages: Parameters<StakingActivateBuilder['messages']>[0]): this {
7+
super.messages(delegateMessages);
8+
this._messages.forEach((message) => (message.typeUrl = constants.wrappedDelegateMsgTypeUrl));
9+
return this;
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as constants from './constants';
2+
import { StakingDeactivateBuilder } from '@bitgo/abstract-cosmos';
3+
4+
export class EpochedStakingDeactivateBuilder extends StakingDeactivateBuilder {
5+
/** @inheritdoc */
6+
messages(undelegateMessages: Parameters<StakingDeactivateBuilder['messages']>[0]): this {
7+
super.messages(undelegateMessages);
8+
this._messages.forEach((message) => (message.typeUrl = constants.wrappedUndelegateMsgTypeUrl));
9+
return this;
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as constants from './constants';
2+
import { StakingRedelegateBuilder } from '@bitgo/abstract-cosmos';
3+
4+
export class EpochedStakingRedelegateBuilder extends StakingRedelegateBuilder {
5+
/** @inheritdoc */
6+
messages(redelegateMessages: Parameters<StakingRedelegateBuilder['messages']>[0]): this {
7+
super.messages(redelegateMessages);
8+
this._messages.forEach((message) => (message.typeUrl = constants.wrappedBeginRedelegateTypeUrl));
9+
return this;
10+
}
11+
}

modules/sdk-coin-baby/src/lib/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ export const contractAddressRegex = /^(bbn)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]
55
export const ADDRESS_PREFIX = 'bbn';
66
export const GAS_AMOUNT = '7000';
77
export const GAS_LIMIT = 200000;
8+
export const wrappedDelegateMsgTypeUrl = '/babylon.epoching.v1.MsgWrappedDelegate';
9+
export const wrappedUndelegateMsgTypeUrl = '/babylon.epoching.v1.MsgWrappedUndelegate';
10+
export const wrappedBeginRedelegateTypeUrl = '/babylon.epoching.v1.MsgWrappedBeginRedelegate';

modules/sdk-coin-baby/src/lib/transactionBuilderFactory.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import {
1010
} from '@bitgo/abstract-cosmos';
1111
import { BaseTransactionBuilderFactory, InvalidTransactionError, TransactionType } from '@bitgo/sdk-core';
1212
import { BaseCoin as CoinConfig } from '@bitgo/statics';
13+
import { EpochedStakingActivateBuilder } from './EpochedStakingActivateBuilder';
14+
import { EpochedStakingDeactivateBuilder } from './EpochedStakingDeactivateBuilder';
15+
import { EpochedStakingRedelegateBuilder } from './EpochedStakingRedelegateBuilder';
1316
import utils from './utils';
1417

1518
export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {
@@ -49,11 +52,11 @@ export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {
4952
}
5053
/** @inheritdoc */
5154
getStakingActivateBuilder(tx?: CosmosTransaction): StakingActivateBuilder {
52-
return this.initializeBuilder(tx, new StakingActivateBuilder(this._coinConfig, utils));
55+
return this.initializeBuilder(tx, new EpochedStakingActivateBuilder(this._coinConfig, utils));
5356
}
5457
/** @inheritdoc */
5558
getStakingDeactivateBuilder(tx?: CosmosTransaction): StakingDeactivateBuilder {
56-
return this.initializeBuilder(tx, new StakingDeactivateBuilder(this._coinConfig, utils));
59+
return this.initializeBuilder(tx, new EpochedStakingDeactivateBuilder(this._coinConfig, utils));
5760
}
5861
/** @inheritdoc */
5962
getStakingWithdrawRewardsBuilder(tx?: CosmosTransaction): StakingWithdrawRewardsBuilder {
@@ -65,7 +68,7 @@ export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {
6568
}
6669

6770
getStakingRedelegateBuilder(tx?: CosmosTransaction): StakingRedelegateBuilder {
68-
return this.initializeBuilder(tx, new StakingRedelegateBuilder(this._coinConfig, utils));
71+
return this.initializeBuilder(tx, new EpochedStakingRedelegateBuilder(this._coinConfig, utils));
6972
}
7073

7174
/** @inheritdoc */

modules/sdk-coin-baby/src/lib/utils.ts

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,81 @@
1-
import { CosmosUtils } from '@bitgo/abstract-cosmos';
2-
import { InvalidTransactionError } from '@bitgo/sdk-core';
1+
import { epochingtx } from '@babylonlabs-io/babylon-proto-ts';
2+
import { DecodedTxRaw } from '@cosmjs/proto-signing';
33
import { Coin } from '@cosmjs/stargate';
44
import BigNumber from 'bignumber.js';
5+
import { Any } from 'cosmjs-types/google/protobuf/any';
6+
import { CosmosUtils, MessageData } from '@bitgo/abstract-cosmos';
7+
import { InvalidTransactionError, TransactionType } from '@bitgo/sdk-core';
58
import * as constants from './constants';
69

710
export class Utils extends CosmosUtils {
11+
protected wrappedMsgTypeUrls = new Set<string>([
12+
constants.wrappedDelegateMsgTypeUrl,
13+
constants.wrappedUndelegateMsgTypeUrl,
14+
constants.wrappedBeginRedelegateTypeUrl,
15+
]);
16+
17+
constructor() {
18+
super();
19+
this.registry.register(constants.wrappedDelegateMsgTypeUrl, epochingtx.MsgWrappedDelegate);
20+
this.registry.register(constants.wrappedUndelegateMsgTypeUrl, epochingtx.MsgWrappedUndelegate);
21+
this.registry.register(constants.wrappedBeginRedelegateTypeUrl, epochingtx.MsgWrappedBeginRedelegate);
22+
}
23+
24+
/** @inheritdoc */
25+
getDelegateOrUndelegateMessageDataFromDecodedTx(decodedTx: DecodedTxRaw): MessageData[] {
26+
return decodedTx.body.messages.map((message) => {
27+
const value = this.registry.decode(message).msg;
28+
return {
29+
typeUrl: message.typeUrl,
30+
value: {
31+
delegatorAddress: value.delegatorAddress,
32+
validatorAddress: value.validatorAddress,
33+
amount: value.amount,
34+
},
35+
};
36+
});
37+
}
38+
39+
/** @inheritdoc */
40+
getRedelegateMessageDataFromDecodedTx(decodedTx: DecodedTxRaw): MessageData[] {
41+
return decodedTx.body.messages.map((message) => {
42+
const value = this.registry.decode(message).msg;
43+
return {
44+
typeUrl: message.typeUrl,
45+
value: {
46+
delegatorAddress: value.delegatorAddress,
47+
validatorSrcAddress: value.validatorSrcAddress,
48+
validatorDstAddress: value.validatorDstAddress,
49+
amount: value.amount,
50+
},
51+
};
52+
});
53+
}
54+
55+
/** @inheritdoc */
56+
getTransactionTypeFromTypeUrl(typeUrl: string): TransactionType | undefined {
57+
switch (typeUrl) {
58+
case constants.wrappedDelegateMsgTypeUrl:
59+
return TransactionType.StakingActivate;
60+
case constants.wrappedUndelegateMsgTypeUrl:
61+
return TransactionType.StakingDeactivate;
62+
case constants.wrappedBeginRedelegateTypeUrl:
63+
return TransactionType.StakingRedelegate;
64+
default:
65+
return super.getTransactionTypeFromTypeUrl(typeUrl);
66+
}
67+
}
68+
69+
/** @inheritdoc */
70+
getSendMessagesForEncodingTx(
71+
cosmosLikeTransaction: Parameters<CosmosUtils['getSendMessagesForEncodingTx']>[0]
72+
): Any[] {
73+
return cosmosLikeTransaction.sendMessages.map(({ typeUrl, value }) => ({
74+
typeUrl,
75+
value: this.wrappedMsgTypeUrls.has(typeUrl) ? { msg: value } : value,
76+
})) as unknown as Any[];
77+
}
78+
879
/** @inheritdoc */
980
isValidAddress(address: string): boolean {
1081
return this.isValidCosmosLikeAddressWithMemoId(address, constants.accountAddressRegex);

modules/sdk-coin-baby/test/resources/baby.ts

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,147 @@ export const TEST_TX_WITH_MEMO = {
157157
},
158158
};
159159

160+
export const TEST_DELEGATE_TX = {
161+
hash: 'EC11EACC2692B1B741D0CEC74FD4E5DA2D9E8875623713ED0EAE63ED43FB5A91',
162+
signature: 'BkwhIYhaVq5UPGEpCUPBCdq59j/JrHCQHn86UiREjL5BqvvPaQZM+hexBpSNoXDokiwoQDQK53VSO4iUumCUGQ==',
163+
pubKey: 'AwT4xoruxA+DkKynr1LH7CM60RwR7Lp5InwQ5ISaN1Hw',
164+
privateKey: 'QAzeAkPWRGyRT8/TvJcRC7VSzQHV9QhH6YTmGZbnvmk=',
165+
signedTxBase64:
166+
'Cp4BCpsBCicvYmFieWxvbi5lcG9jaGluZy52MS5Nc2dXcmFwcGVkRGVsZWdhdGUScApuCipiYm4xMjc0ZXA4cG5ybGVqNXZnbXR3cHB5c3luemNkNGZoeGMza3UwdDMSMWJibnZhbG9wZXIxemw3OGV6aGd3NmZxeHlkZWNubWNteWRzbTBndHJqZHRhbm03bnIaDQoEdWJibhIFMTAwMDASZQpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAwT4xoruxA+DkKynr1LH7CM60RwR7Lp5InwQ5ISaN1HwEgQKAggBGB0SEQoLCgR1YmJuEgM1MDAQwJoMGkAGTCEhiFpWrlQ8YSkJQ8EJ2rn2P8mscJAefzpSJESMvkGq+89pBkz6F7EGlI2hcOiSLChANArndVI7iJS6YJQZ',
167+
from: 'bbn1274ep8pnrlej5vgmtwppysynzcd4fhxc3ku0t3',
168+
to: 'bbnvaloper1zl78ezhgw6fqxydecnmcmydsm0gtrjdtanm7nr',
169+
chainId: 'bbn-test-5',
170+
accountNumber: 59235,
171+
sequence: 29,
172+
sendAmount: '10000',
173+
feeAmount: '500',
174+
sendMessage: {
175+
typeUrl: '/babylon.epoching.v1.MsgWrappedDelegate',
176+
value: {
177+
delegatorAddress: 'bbn1274ep8pnrlej5vgmtwppysynzcd4fhxc3ku0t3',
178+
validatorAddress: 'bbnvaloper1zl78ezhgw6fqxydecnmcmydsm0gtrjdtanm7nr',
179+
amount: {
180+
denom: 'ubbn',
181+
amount: '10000',
182+
},
183+
},
184+
},
185+
gasBudget: {
186+
amount: [
187+
{
188+
denom: 'ubbn',
189+
amount: '500',
190+
},
191+
],
192+
gasLimit: 200000,
193+
},
194+
};
195+
196+
export const TEST_UNDELEGATE_TX = {
197+
hash: '009D9A8F17B4DB99B86F1EBAFC801AA2A887E89D4D20EAE2FE30203484A3273E',
198+
signature: 'm8XIY/88A66uBWShNLGFxLqgftFF18dpqni4ChvS6Wsn+xZCqZhcrpoJbmLzaFTRp+YnPvLawLy0QEAkff5NyA==',
199+
pubKey: 'AwT4xoruxA+DkKynr1LH7CM60RwR7Lp5InwQ5ISaN1Hw',
200+
privateKey: 'QAzeAkPWRGyRT8/TvJcRC7VSzQHV9QhH6YTmGZbnvmk=',
201+
signedTxBase64:
202+
'CqABCp0BCikvYmFieWxvbi5lcG9jaGluZy52MS5Nc2dXcmFwcGVkVW5kZWxlZ2F0ZRJwCm4KKmJibjEyNzRlcDhwbnJsZWo1dmdtdHdwcHlzeW56Y2Q0Zmh4YzNrdTB0MxIxYmJudmFsb3BlcjF6bDc4ZXpoZ3c2ZnF4eWRlY25tY215ZHNtMGd0cmpkdGFubTduchoNCgR1YmJuEgUxMDAwMBJlClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDBPjGiu7ED4OQrKevUsfsIzrRHBHsunkifBDkhJo3UfASBAoCCAEYHhIRCgsKBHViYm4SAzUwMBDAmgwaQJvFyGP/PAOurgVkoTSxhcS6oH7RRdfHaap4uAob0ulrJ/sWQqmYXK6aCW5i82hU0afmJz7y2sC8tEBAJH3+Tcg=',
203+
from: 'bbn1274ep8pnrlej5vgmtwppysynzcd4fhxc3ku0t3',
204+
to: 'bbnvaloper1zl78ezhgw6fqxydecnmcmydsm0gtrjdtanm7nr',
205+
chainId: 'bbn-test-5',
206+
accountNumber: 59235,
207+
sequence: 30,
208+
sendAmount: '10000',
209+
feeAmount: '500',
210+
sendMessage: {
211+
typeUrl: '/babylon.epoching.v1.MsgWrappedUndelegate',
212+
value: {
213+
delegatorAddress: 'bbn1274ep8pnrlej5vgmtwppysynzcd4fhxc3ku0t3',
214+
validatorAddress: 'bbnvaloper1zl78ezhgw6fqxydecnmcmydsm0gtrjdtanm7nr',
215+
amount: {
216+
denom: 'ubbn',
217+
amount: '10000',
218+
},
219+
},
220+
},
221+
gasBudget: {
222+
amount: [
223+
{
224+
denom: 'ubbn',
225+
amount: '500',
226+
},
227+
],
228+
gasLimit: 200000,
229+
},
230+
};
231+
232+
export const TEST_REDELEGATE_TX = {
233+
hash: 'CC45369A75E76D3287A3831853369EEE6C5D1B5FB4277CC4FA0D4D06A0DFA661',
234+
signature: 'bJlHHrfB08ypEZkSzy6wbqvNJhGB6OgPd2quqW5GqNYPtBniVHiS0jjVwgoldkM0cLdj8EilWP663Donqci8Aw==',
235+
pubKey: 'AwT4xoruxA+DkKynr1LH7CM60RwR7Lp5InwQ5ISaN1Hw',
236+
privateKey: 'QAzeAkPWRGyRT8/TvJcRC7VSzQHV9QhH6YTmGZbnvmk=',
237+
signedTxBase64:
238+
'CtoBCtcBCi4vYmFieWxvbi5lcG9jaGluZy52MS5Nc2dXcmFwcGVkQmVnaW5SZWRlbGVnYXRlEqQBCqEBCipiYm4xMjc0ZXA4cG5ybGVqNXZnbXR3cHB5c3luemNkNGZoeGMza3UwdDMSMWJibnZhbG9wZXIxemw3OGV6aGd3NmZxeHlkZWNubWNteWRzbTBndHJqZHRhbm03bnIaMWJibnZhbG9wZXIxMmptOXo2aHdtNGV4N2MwejhodGV5M3loeWZoeDQ0em43MGE1bDYiDQoEdWJibhIFMTAwMDASZQpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAwT4xoruxA+DkKynr1LH7CM60RwR7Lp5InwQ5ISaN1HwEgQKAggBGB8SEQoLCgR1YmJuEgM1MDAQwJoMGkBsmUcet8HTzKkRmRLPLrBuq80mEYHo6A93aq6pbkao1g+0GeJUeJLSONXCCiV2QzRwt2PwSKVY/rrcOiepyLwD',
239+
delegator: 'bbn1274ep8pnrlej5vgmtwppysynzcd4fhxc3ku0t3',
240+
validator: 'bbnvaloper12jm9z6hwm4ex7c0z8htey3yhyfhx44zn70a5l6',
241+
chainId: 'bbn-test-5',
242+
accountNumber: 59235,
243+
sequence: 31,
244+
sendAmount: '10000',
245+
feeAmount: '500',
246+
sendMessage: {
247+
typeUrl: '/babylon.epoching.v1.MsgWrappedBeginRedelegate',
248+
value: {
249+
delegatorAddress: 'bbn1274ep8pnrlej5vgmtwppysynzcd4fhxc3ku0t3',
250+
validatorSrcAddress: 'bbnvaloper1zl78ezhgw6fqxydecnmcmydsm0gtrjdtanm7nr',
251+
validatorDstAddress: 'bbnvaloper12jm9z6hwm4ex7c0z8htey3yhyfhx44zn70a5l6',
252+
amount: {
253+
denom: 'ubbn',
254+
amount: '10000',
255+
},
256+
},
257+
},
258+
gasBudget: {
259+
amount: [
260+
{
261+
denom: 'ubbn',
262+
amount: '500',
263+
},
264+
],
265+
gasLimit: 200000,
266+
},
267+
};
268+
269+
export const TEST_WITHDRAW_REWARDS_TX = {
270+
hash: 'EA4ECA4DA17B158238242572AD9A7E7734D7085BF679555EE90FA4F0EF3CFA79',
271+
signature: 'vyVU/1zVhp6m0uMF5mLaKr3o/Oe36O+EF3E7Dgw7smlUjOW5Ttwgnl44zO1vro4MU2frc/KV4Ji2IqWKi8QlLA==',
272+
pubKey: 'AwT4xoruxA+DkKynr1LH7CM60RwR7Lp5InwQ5ISaN1Hw',
273+
privateKey: 'QAzeAkPWRGyRT8/TvJcRC7VSzQHV9QhH6YTmGZbnvmk=',
274+
signedTxBase64:
275+
'Cp0BCpoBCjcvY29zbW9zLmRpc3RyaWJ1dGlvbi52MWJldGExLk1zZ1dpdGhkcmF3RGVsZWdhdG9yUmV3YXJkEl8KKmJibjEyNzRlcDhwbnJsZWo1dmdtdHdwcHlzeW56Y2Q0Zmh4YzNrdTB0MxIxYmJudmFsb3BlcjF6bDc4ZXpoZ3c2ZnF4eWRlY25tY215ZHNtMGd0cmpkdGFubTduchJlClAKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiEDBPjGiu7ED4OQrKevUsfsIzrRHBHsunkifBDkhJo3UfASBAoCCAEYIBIRCgsKBHViYm4SAzUwMBDAmgwaQL8lVP9c1YaeptLjBeZi2iq96Pznt+jvhBdxOw4MO7JpVIzluU7cIJ5eOMztb66ODFNn63PyleCYtiKliovEJSw=',
276+
from: 'bbn1274ep8pnrlej5vgmtwppysynzcd4fhxc3ku0t3',
277+
to: 'bbnvaloper1zl78ezhgw6fqxydecnmcmydsm0gtrjdtanm7nr',
278+
chainId: 'bbn-test-5',
279+
accountNumber: 59235,
280+
sequence: 32,
281+
sendAmount: '10000',
282+
feeAmount: '500',
283+
sendMessage: {
284+
typeUrl: '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward',
285+
value: {
286+
delegatorAddress: 'bbn1274ep8pnrlej5vgmtwppysynzcd4fhxc3ku0t3',
287+
validatorAddress: 'bbnvaloper1zl78ezhgw6fqxydecnmcmydsm0gtrjdtanm7nr',
288+
},
289+
},
290+
gasBudget: {
291+
amount: [
292+
{
293+
denom: 'ubbn',
294+
amount: '500',
295+
},
296+
],
297+
gasLimit: 200000,
298+
},
299+
};
300+
160301
export const address = {
161302
address1: 'bbn1897xa4swxx9dr7z0zut0mfs7efplx80q86kd8q',
162303
address2: 'bbn1274ep8pnrlej5vgmtwppysynzcd4fhxc3ku0t3',

0 commit comments

Comments
 (0)