Skip to content

Commit 7b4fbdb

Browse files
committed
feat: staking support cronos
Ticket: SC-2124
1 parent 0a55075 commit 7b4fbdb

File tree

5 files changed

+435
-0
lines changed

5 files changed

+435
-0
lines changed

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

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,129 @@ export const coinAmounts = {
192192
amount4: { amount: '-1', denom: 'basetcro' },
193193
amount5: { amount: '1000000000', denom: 'mbasetcro' },
194194
};
195+
196+
export const TEST_DELEGATE_TX = {
197+
hash: '01BA59AAF0EC2AAAB8B036B16C27E654C57822BEB8AE3FDDC22C31D5ED7521D8',
198+
signature: '5H3a5WlZS3yvL+muU8qPB1IlYBxvuu7vIDOQuIc0JMU06kNtj8arKQLH9NGEpweu3u84KXYURA+Qxo8AzoO8Zw==',
199+
pubKey: 'AtlNaLjd5ijapNfxJCzOJV4pdMBouEomADHNgQEPulHL',
200+
privateKey: 'peFJjp2ECSNTRdKBfVhv8aGgoUBbmYPp2+l9prY5zjc=',
201+
signedTxBase64:
202+
'CpkBCpYBCiMvY29zbW9zLnN0YWtpbmcudjFiZXRhMS5Nc2dEZWxlZ2F0ZRJvCit0Y3JvMXJoczQwMnZuamY3MzY5eXlqa2swbnJza3VwbWZsNHl4cG5hYWhqEi90Y3JvY25jbDFzNGdncTJ6dXp2d2c1azh2bngyeGZ3dGRtNGN6Nnd0bnVxa2w3YRoPCghiYXNldGNybxIDMTAwEmoKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQLZTWi43eYo2qTX8SQsziVeKXTAaLhKJgAxzYEBD7pRyxIECgIIARgKEhYKEAoIYmFzZXRjcm8SBDUwMDAQwJoMGkDkfdrlaVlLfK8v6a5Tyo8HUiVgHG+67u8gM5C4hzQkxTTqQ22PxqspAsf00YSnB67e7zgpdhRED5DGjwDOg7xn',
203+
delegator: 'tcro1rhs402vnjf7369yyjkk0nrskupmfl4yxpnaahj',
204+
validator: 'tcrocncl1s4ggq2zuzvwg5k8vnx2xfwtdm4cz6wtnuqkl7a',
205+
chainId: 'testnet-croeseid-4',
206+
accountNumber: 10,
207+
sequence: 10,
208+
sendAmount: '100',
209+
feeAmount: '5000',
210+
sendMessage: {
211+
typeUrl: '/cosmos.staking.v1beta1.MsgDelegate',
212+
value: {
213+
delegatorAddress: 'tcro1rhs402vnjf7369yyjkk0nrskupmfl4yxpnaahj',
214+
validatorAddress: 'tcrocncl1s4ggq2zuzvwg5k8vnx2xfwtdm4cz6wtnuqkl7a',
215+
amount: {
216+
denom: 'basetcro',
217+
amount: '100',
218+
},
219+
},
220+
},
221+
gasBudget: {
222+
amount: [{ denom: 'basetcro', amount: '5000' }],
223+
gasLimit: 200000,
224+
},
225+
};
226+
227+
export const TEST_UNDELEGATE_TX = {
228+
hash: '0148F45CD290B9D4A5594ACC49707C362A3275AE00F881776BE2B8929FC3A430',
229+
signature: '5H3a5WlZS3yvL+muU8qPB1IlYBxvuu7vIDOQuIc0JMU06kNtj8arKQLH9NGEpweu3u84KXYURA+Qxo8AzoO8Zw==',
230+
pubKey: 'AtlNaLjd5ijapNfxJCzOJV4pdMBouEomADHNgQEPulHL',
231+
privateKey: 'peFJjp2ECSNTRdKBfVhv8aGgoUBbmYPp2+l9prY5zjc=',
232+
signedTxBase64:
233+
'CpsBCpgBCiUvY29zbW9zLnN0YWtpbmcudjFiZXRhMS5Nc2dVbmRlbGVnYXRlEm8KK3Rjcm8xcmhzNDAydm5qZjczNjl5eWprazBucnNrdXBtZmw0eXhwbmFhaGoSL3Rjcm9jbmNsMXM0Z2dxMnp1enZ3ZzVrOHZueDJ4Znd0ZG00Y3o2d3RudXFrbDdhGg8KCGJhc2V0Y3JvEgMxMDASawpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAtlNaLjd5ijapNfxJCzOJV4pdMBouEomADHNgQEPulHLEgQKAggBGAoSFwoRCghiYXNldGNybxIFNTAwMDAQwJoMGkDkfdrlaVlLfK8v6a5Tyo8HUiVgHG+67u8gM5C4hzQkxTTqQ22PxqspAsf00YSnB67e7zgpdhRED5DGjwDOg7xn',
234+
delegator: 'tcro1rhs402vnjf7369yyjkk0nrskupmfl4yxpnaahj',
235+
validator: 'tcrocncl1s4ggq2zuzvwg5k8vnx2xfwtdm4cz6wtnuqkl7a',
236+
chainId: 'testnet-croeseid-4',
237+
accountNumber: 10,
238+
sequence: 10,
239+
sendAmount: '100',
240+
feeAmount: '5000',
241+
sendMessage: {
242+
typeUrl: '/cosmos.staking.v1beta1.MsgUndelegate',
243+
value: {
244+
delegatorAddress: 'tcro1rhs402vnjf7369yyjkk0nrskupmfl4yxpnaahj',
245+
validatorAddress: 'tcrocncl1s4ggq2zuzvwg5k8vnx2xfwtdm4cz6wtnuqkl7a',
246+
amount: {
247+
denom: 'basetcro',
248+
amount: '100',
249+
},
250+
},
251+
},
252+
gasBudget: {
253+
amount: [
254+
{
255+
denom: 'basetcro',
256+
amount: '50000',
257+
},
258+
],
259+
gasLimit: 200000,
260+
},
261+
};
262+
263+
export const TEST_REDELEGATE_TX = {
264+
hash: '01BDED57D2A48B9CC3F47AFE9BFFEB934ABC0E83B83E9DF8B60C1C0843583A46',
265+
signature: '5H3a5WlZS3yvL+muU8qPB1IlYBxvuu7vIDOQuIc0JMU06kNtj8arKQLH9NGEpweu3u84KXYURA+Qxo8AzoO8Zw==',
266+
pubKey: 'AtlNaLjd5ijapNfxJCzOJV4pdMBouEomADHNgQEPulHL',
267+
privateKey: 'peFJjp2ECSNTRdKBfVhv8aGgoUBbmYPp2+l9prY5zjc=',
268+
signedTxBase64:
269+
'CtIBCs8BCiovY29zbW9zLnN0YWtpbmcudjFiZXRhMS5Nc2dCZWdpblJlZGVsZWdhdGUSoAEKK3Rjcm8xcmhzNDAydm5qZjczNjl5eWprazBucnNrdXBtZmw0eXhwbmFhaGoSL3Rjcm9jbmNsMXM0Z2dxMnp1enZ3ZzVrOHZueDJ4Znd0ZG00Y3o2d3RudXFrbDdhGi90Y3JvY25jbDE2M3R2NTl5emdlcWNhcDhscnNhMnI0ems1ODBoOGRkcjVhMHNkZCIPCghiYXNldGNybxIDMTAwEmoKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQLZTWi43eYo2qTX8SQsziVeKXTAaLhKJgAxzYEBD7pRyxIECgIIARgKEhYKEAoIYmFzZXRjcm8SBDgwMDAQ4KcSGkDkfdrlaVlLfK8v6a5Tyo8HUiVgHG+67u8gM5C4hzQkxTTqQ22PxqspAsf00YSnB67e7zgpdhRED5DGjwDOg7xn',
270+
delegator: 'tcro1rhs402vnjf7369yyjkk0nrskupmfl4yxpnaahj',
271+
validator: 'tcrocncl1s4ggq2zuzvwg5k8vnx2xfwtdm4cz6wtnuqkl7a',
272+
validatorDst: 'tcrocncl163tv59yzgeqcap8lrsa2r4zk580h8ddr5a0sdd',
273+
chainId: 'testnet-croeseid-4',
274+
accountNumber: 10,
275+
sequence: 10,
276+
sendAmount: '100',
277+
feeAmount: '5000',
278+
sendMessage: {
279+
typeUrl: '/cosmos.staking.v1beta1.MsgBeginRedelegate',
280+
value: {
281+
delegatorAddress: 'tcro1rhs402vnjf7369yyjkk0nrskupmfl4yxpnaahj',
282+
validatorSrcAddress: 'tcrocncl1s4ggq2zuzvwg5k8vnx2xfwtdm4cz6wtnuqkl7a',
283+
validatorDstAddress: 'tcrocncl163tv59yzgeqcap8lrsa2r4zk580h8ddr5a0sdd',
284+
amount: {
285+
denom: 'basetcro',
286+
amount: '100',
287+
},
288+
},
289+
},
290+
gasBudget: {
291+
amount: [{ denom: 'basetcro', amount: '8000' }],
292+
gasLimit: 300000,
293+
},
294+
};
295+
296+
export const TEST_WITHDRAW_REWARDS_TX = {
297+
hash: '4CAA5DDBFB138D555DDDEFC8E256BDD3CFC201C6C71DC3BB245A412EB29CB49A',
298+
signature: '5H3a5WlZS3yvL+muU8qPB1IlYBxvuu7vIDOQuIc0JMU06kNtj8arKQLH9NGEpweu3u84KXYURA+Qxo8AzoO8Zw==',
299+
pubKey: 'AtlNaLjd5ijapNfxJCzOJV4pdMBouEomADHNgQEPulHL',
300+
privateKey: 'peFJjp2ECSNTRdKBfVhv8aGgoUBbmYPp2+l9prY5zjc=',
301+
signedTxBase64:
302+
'CpwBCpkBCjcvY29zbW9zLmRpc3RyaWJ1dGlvbi52MWJldGExLk1zZ1dpdGhkcmF3RGVsZWdhdG9yUmV3YXJkEl4KK3Rjcm8xcmhzNDAydm5qZjczNjl5eWprazBucnNrdXBtZmw0eXhwbmFhaGoSL3Rjcm9jbmNsMXM0Z2dxMnp1enZ3ZzVrOHZueDJ4Znd0ZG00Y3o2d3RudXFrbDdhEmoKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQLZTWi43eYo2qTX8SQsziVeKXTAaLhKJgAxzYEBD7pRyxIECgIIARgKEhYKEAoIYmFzZXRjcm8SBDUwMDAQwJoMGkDkfdrlaVlLfK8v6a5Tyo8HUiVgHG+67u8gM5C4hzQkxTTqQ22PxqspAsf00YSnB67e7zgpdhRED5DGjwDOg7xn',
303+
delegator: 'tcro1rhs402vnjf7369yyjkk0nrskupmfl4yxpnaahj',
304+
validator: 'tcrocncl1s4ggq2zuzvwg5k8vnx2xfwtdm4cz6wtnuqkl7a',
305+
chainId: 'testnet-croeseid-4',
306+
accountNumber: 10,
307+
sequence: 10,
308+
feeAmount: '50000',
309+
sendMessage: {
310+
typeUrl: '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward',
311+
value: {
312+
delegatorAddress: 'tcro1rhs402vnjf7369yyjkk0nrskupmfl4yxpnaahj',
313+
validatorAddress: 'tcrocncl1s4ggq2zuzvwg5k8vnx2xfwtdm4cz6wtnuqkl7a',
314+
},
315+
},
316+
gasBudget: {
317+
amount: [{ denom: 'basetcro', amount: '5000' }],
318+
gasLimit: 200000,
319+
},
320+
};
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { toHex, TransactionType } from '@bitgo/sdk-core';
2+
import { fromBase64 } from '@cosmjs/encoding';
3+
import axios from 'axios';
4+
import should from 'should';
5+
import * as testData from '../../resources/cronos';
6+
import { KeyPair } from '../../../src';
7+
import { getBuilderFactory } from '../getBuilderFactory';
8+
9+
describe('Cronos delegate transaction builder', () => {
10+
const factory = getBuilderFactory('tcronos');
11+
const testTx = testData.TEST_DELEGATE_TX;
12+
it('should build a Delegate transaction with signature', async function () {
13+
const txBuilder = factory.getStakingActivateBuilder();
14+
txBuilder.sequence(testTx.sequence);
15+
txBuilder.gasBudget(testTx.gasBudget);
16+
txBuilder.messages([testTx.sendMessage.value]);
17+
txBuilder.publicKey(toHex(fromBase64(testTx.pubKey)));
18+
txBuilder.addSignature({ pub: toHex(fromBase64(testTx.pubKey)) }, Buffer.from(testTx.signature, 'base64'));
19+
20+
const tx = await txBuilder.build();
21+
const json = await (await txBuilder.build()).toJson();
22+
should.equal(tx.type, TransactionType.StakingActivate);
23+
should.deepEqual(json.gasBudget, testTx.gasBudget);
24+
should.deepEqual(json.sendMessages, [testTx.sendMessage]);
25+
should.deepEqual(json.publicKey, toHex(fromBase64(testTx.pubKey)));
26+
should.deepEqual(json.sequence, testTx.sequence);
27+
const rawTx = tx.toBroadcastFormat();
28+
should.equal(rawTx, testTx.signedTxBase64);
29+
should.deepEqual(tx.inputs, [
30+
{
31+
address: testTx.delegator,
32+
value: testTx.sendMessage.value.amount.amount,
33+
coin: 'tcronos',
34+
},
35+
]);
36+
should.deepEqual(tx.outputs, [
37+
{
38+
address: testTx.validator,
39+
value: testTx.sendMessage.value.amount.amount,
40+
coin: 'tcronos',
41+
},
42+
]);
43+
});
44+
45+
it('should build a Delegate tx without signature', async function () {
46+
const txBuilder = factory.getStakingActivateBuilder();
47+
txBuilder.sequence(testTx.sequence);
48+
txBuilder.gasBudget(testTx.gasBudget);
49+
txBuilder.messages([testTx.sendMessage.value]);
50+
txBuilder.publicKey(toHex(fromBase64(testTx.pubKey)));
51+
const tx = await txBuilder.build();
52+
const json = await (await txBuilder.build()).toJson();
53+
should.equal(tx.type, TransactionType.StakingActivate);
54+
should.deepEqual(json.gasBudget, testTx.gasBudget);
55+
should.deepEqual(json.sendMessages, [testTx.sendMessage]);
56+
should.deepEqual(json.publicKey, toHex(fromBase64(testTx.pubKey)));
57+
should.deepEqual(json.sequence, testTx.sequence);
58+
tx.toBroadcastFormat();
59+
should.deepEqual(tx.inputs, [
60+
{
61+
address: testTx.delegator,
62+
value: testTx.sendMessage.value.amount.amount,
63+
coin: 'tcronos',
64+
},
65+
]);
66+
should.deepEqual(tx.outputs, [
67+
{
68+
address: testTx.validator,
69+
value: testTx.sendMessage.value.amount.amount,
70+
coin: 'tcronos',
71+
},
72+
]);
73+
});
74+
75+
xit('should submit a send transaction', async () => {
76+
const keyPair = new KeyPair({ prv: toHex(fromBase64(testTx.privateKey)) });
77+
const axiosConfig = {
78+
headers: {
79+
'Content-Type': 'application/cbor',
80+
},
81+
timeout: 10000,
82+
};
83+
84+
const txBuilder = factory.getStakingActivateBuilder();
85+
txBuilder.sequence(10);
86+
txBuilder.gasBudget(testTx.gasBudget);
87+
txBuilder.messages([testTx.sendMessage.value]);
88+
txBuilder.accountNumber(testTx.accountNumber);
89+
txBuilder.chainId(testTx.chainId);
90+
txBuilder.sign({ key: keyPair.getKeys().prv });
91+
const tx = await txBuilder.build();
92+
const serializedTx = tx.toBroadcastFormat();
93+
94+
try {
95+
const res = await axios.post(
96+
'https://rest.sentry-01.theta-testnet.polypore.xyz/cosmos/tx/v1beta1/txs',
97+
{
98+
mode: 'BROADCAST_MODE_BLOCK',
99+
tx_bytes: serializedTx,
100+
},
101+
axiosConfig
102+
);
103+
console.log(res);
104+
} catch (err) {
105+
console.log(err);
106+
}
107+
});
108+
});
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { toHex, TransactionType } from '@bitgo/sdk-core';
2+
import { fromBase64 } from '@cosmjs/encoding';
3+
import should from 'should';
4+
5+
import * as testData from '../../resources/cronos';
6+
import { getBuilderFactory } from '../getBuilderFactory';
7+
8+
describe('Cronos Undelegate txn Builder', () => {
9+
const factory = getBuilderFactory('tcronos');
10+
const testTx = testData.TEST_UNDELEGATE_TX;
11+
it('should build undelegate tx with signature', async function () {
12+
const txBuilder = factory.getStakingDeactivateBuilder();
13+
txBuilder.sequence(testTx.sequence);
14+
txBuilder.gasBudget(testTx.gasBudget);
15+
txBuilder.messages([testTx.sendMessage.value]);
16+
txBuilder.addSignature({ pub: toHex(fromBase64(testTx.pubKey)) }, Buffer.from(testTx.signature, 'base64'));
17+
const tx = await txBuilder.build();
18+
const json = await (await txBuilder.build()).toJson();
19+
should.equal(tx.type, TransactionType.StakingDeactivate);
20+
should.deepEqual(json.gasBudget, testTx.gasBudget);
21+
should.deepEqual(json.sendMessages, [testTx.sendMessage]);
22+
should.deepEqual(json.publicKey, toHex(fromBase64(testTx.pubKey)));
23+
should.deepEqual(json.sequence, testTx.sequence);
24+
const rawTx = tx.toBroadcastFormat();
25+
should.equal(rawTx, testTx.signedTxBase64);
26+
should.deepEqual(tx.inputs, [
27+
{
28+
address: testTx.delegator,
29+
value: testTx.sendMessage.value.amount.amount,
30+
coin: 'tcronos',
31+
},
32+
]);
33+
should.deepEqual(tx.outputs, [
34+
{
35+
address: testTx.validator,
36+
value: testTx.sendMessage.value.amount.amount,
37+
coin: 'tcronos',
38+
},
39+
]);
40+
});
41+
42+
it('should build undelegate tx without signature', async function () {
43+
const txBuilder = factory.getStakingDeactivateBuilder();
44+
txBuilder.sequence(testTx.sequence);
45+
txBuilder.gasBudget(testTx.gasBudget);
46+
txBuilder.messages([testTx.sendMessage.value]);
47+
txBuilder.publicKey(toHex(fromBase64(testTx.pubKey)));
48+
const tx = await txBuilder.build();
49+
const json = await (await txBuilder.build()).toJson();
50+
should.equal(tx.type, TransactionType.StakingDeactivate);
51+
should.deepEqual(json.gasBudget, testTx.gasBudget);
52+
should.deepEqual(json.sendMessages, [testTx.sendMessage]);
53+
should.deepEqual(json.publicKey, toHex(fromBase64(testTx.pubKey)));
54+
should.deepEqual(json.sequence, testTx.sequence);
55+
tx.toBroadcastFormat();
56+
should.deepEqual(tx.inputs, [
57+
{
58+
address: testTx.delegator,
59+
value: testTx.sendMessage.value.amount.amount,
60+
coin: 'tcronos',
61+
},
62+
]);
63+
should.deepEqual(tx.outputs, [
64+
{
65+
address: testTx.validator,
66+
value: testTx.sendMessage.value.amount.amount,
67+
coin: 'tcronos',
68+
},
69+
]);
70+
});
71+
});
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { BitGoAPI } from '@bitgo/sdk-api';
2+
import { toHex, TransactionType } from '@bitgo/sdk-core';
3+
import { TestBitGo, TestBitGoAPI } from '@bitgo/sdk-test';
4+
import { fromBase64 } from '@cosmjs/encoding';
5+
import should from 'should';
6+
import { Cronos, Tcronos } from '../../../src';
7+
import * as testData from '../../resources/cronos';
8+
9+
describe('Cronos Redelegate txn Builder', () => {
10+
let bitgo: TestBitGoAPI;
11+
let basecoin;
12+
let factory;
13+
let testTx;
14+
before(function () {
15+
bitgo = TestBitGo.decorate(BitGoAPI, { env: 'mock' });
16+
bitgo.safeRegister('cronos', Cronos.createInstance);
17+
bitgo.safeRegister('tcronos', Tcronos.createInstance);
18+
bitgo.initializeTestVars();
19+
basecoin = bitgo.coin('tcronos');
20+
factory = basecoin.getBuilder();
21+
testTx = testData.TEST_REDELEGATE_TX;
22+
});
23+
24+
it('should build a Redelegate tx with signature', async function () {
25+
const txBuilder = factory.getStakingRedelegateBuilder();
26+
txBuilder.sequence(testTx.sequence);
27+
txBuilder.gasBudget(testTx.gasBudget);
28+
txBuilder.messages([testTx.sendMessage.value]);
29+
txBuilder.memo('');
30+
txBuilder.publicKey(toHex(fromBase64(testTx.pubKey)));
31+
txBuilder.addSignature({ pub: toHex(fromBase64(testTx.pubKey)) }, Buffer.from(testTx.signature, 'base64'));
32+
33+
const tx = await txBuilder.build();
34+
const json = await (await txBuilder.build()).toJson();
35+
should.equal(tx.type, TransactionType.StakingRedelegate);
36+
should.deepEqual(json.gasBudget, testTx.gasBudget);
37+
should.deepEqual(json.sendMessages, [testTx.sendMessage]);
38+
should.deepEqual(json.publicKey, toHex(fromBase64(testTx.pubKey)));
39+
should.deepEqual(json.sequence, testTx.sequence);
40+
const rawTx = tx.toBroadcastFormat();
41+
should.equal(rawTx, testTx.signedTxBase64);
42+
should.deepEqual(tx.inputs, [
43+
{
44+
address: testTx.delegator,
45+
value: testTx.sendMessage.value.amount.amount,
46+
coin: basecoin.getChain(),
47+
},
48+
]);
49+
should.deepEqual(tx.outputs, [
50+
{
51+
address: testTx.validatorDst,
52+
value: testTx.sendMessage.value.amount.amount,
53+
coin: basecoin.getChain(),
54+
},
55+
]);
56+
});
57+
});

0 commit comments

Comments
 (0)