Skip to content

Commit 398815d

Browse files
authored
Merge pull request #6107 from BitGo/COIN-4030-sdk-intia
feat(sdk-coin-init): add SDK support for Initia
2 parents 9e77a92 + c1f4db3 commit 398815d

File tree

14 files changed

+1067
-34
lines changed

14 files changed

+1067
-34
lines changed

modules/sdk-coin-fetch/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
"@cosmjs/stargate": "^0.29.5",
4747
"@cosmjs/amino": "^0.29.5",
4848
"@cosmjs/encoding": "^0.29.5",
49-
"@cosmjs/stargate": "^0.29.5",
5049
"bignumber.js": "^9.1.1"
5150
},
5251
"devDependencies": {

modules/sdk-coin-init/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@
4343
"@bitgo/abstract-cosmos": "^11.7.3",
4444
"@bitgo/sdk-core": "^33.2.0",
4545
"@bitgo/statics": "^52.2.0",
46-
"@cosmjs/stargate": "^0.29.5"
46+
"@cosmjs/stargate": "^0.29.5",
47+
"@cosmjs/amino": "^0.29.5",
48+
"@cosmjs/encoding": "^0.29.5",
49+
"bignumber.js": "^9.1.1"
4750
},
4851
"devDependencies": {
4952
"@bitgo/sdk-api": "^1.62.3",

modules/sdk-coin-init/src/init.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1-
import { BaseCoin, BitGoBase } from '@bitgo/sdk-core';
2-
import { BaseCoin as StaticsBaseCoin } from '@bitgo/statics';
1+
import { BaseCoin, BitGoBase, Environments } from '@bitgo/sdk-core';
2+
import { BaseUnit, BaseCoin as StaticsBaseCoin, coins } from '@bitgo/statics';
33
import { CosmosCoin, CosmosKeyPair, GasAmountDetails } from '@bitgo/abstract-cosmos';
4-
import { TransactionBuilderFactory } from './lib';
4+
import { KeyPair, TransactionBuilderFactory } from './lib';
5+
import { GAS_AMOUNT, GAS_LIMIT } from './lib/constants';
6+
import utils from './lib/utils';
57

8+
/**
9+
*
10+
* Full Name: Initia
11+
* Website: https://initia.xyz/
12+
* Docs: https://docs.initia.xyz/
13+
* GitHub : https://github.com/initia-labs
14+
*/
615
export class Init extends CosmosCoin {
716
protected readonly _staticsCoin: Readonly<StaticsBaseCoin>;
817

@@ -27,36 +36,39 @@ export class Init extends CosmosCoin {
2736

2837
/** @inheritDoc **/
2938
getBuilder(): TransactionBuilderFactory {
30-
throw new Error('Method not implemented.');
39+
return new TransactionBuilderFactory(coins.get(this.getChain()));
3140
}
3241

3342
/** @inheritDoc **/
3443
isValidAddress(address: string): boolean {
35-
throw new Error('Method not implemented.');
44+
return utils.isValidAddress(address) || utils.isValidValidatorAddress(address);
3645
}
3746

3847
/** @inheritDoc **/
3948
getDenomination(): string {
40-
throw new Error('Method not implemented');
49+
return BaseUnit.INIT;
4150
}
4251

4352
/** @inheritDoc **/
4453
getGasAmountDetails(): GasAmountDetails {
45-
throw new Error('Method not implemented');
54+
return {
55+
gasAmount: GAS_AMOUNT,
56+
gasLimit: GAS_LIMIT,
57+
};
4658
}
4759

4860
/** @inheritDoc **/
4961
getKeyPair(publicKey: string): CosmosKeyPair {
50-
throw new Error('Method not implemented');
62+
return new KeyPair({ pub: publicKey });
5163
}
5264

5365
/** @inheritDoc **/
5466
protected getPublicNodeUrl(): string {
55-
throw new Error('Method not implemented');
67+
return Environments[this.bitgo.getEnv()].initNodeUrl;
5668
}
5769

5870
/** @inheritDoc **/
5971
getAddressFromPublicKey(pubKey: string): string {
60-
throw new Error('Method not implemented');
72+
return new KeyPair({ pub: pubKey }).getAddress();
6173
}
6274
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const validDenoms = ['init', 'tinit', 'uinit'];
2+
export const accountAddressRegex = /^(init)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38})$/;
3+
export const validatorAddressRegex = /^(initvaloper)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38})$/;
4+
export const contractAddressRegex = /^(init)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]+)$/;
5+
export const ADDRESS_PREFIX = 'init';
6+
export const GAS_AMOUNT = '30000';
7+
export const GAS_LIMIT = 500000;

modules/sdk-coin-init/src/lib/keyPair.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { KeyPairOptions } from '@bitgo/sdk-core';
2+
import { pubkeyToAddress } from '@cosmjs/amino';
23
import { CosmosKeyPair } from '@bitgo/abstract-cosmos';
4+
import { ADDRESS_PREFIX } from './constants';
35

46
/**
57
* Initia keys and address management.
@@ -11,6 +13,13 @@ export class KeyPair extends CosmosKeyPair {
1113

1214
/** @inheritdoc */
1315
getAddress(): string {
14-
throw new Error('Method not implemented.');
16+
const base64String = Buffer.from(this.getKeys().pub.slice(0, 66), 'hex').toString('base64');
17+
return pubkeyToAddress(
18+
{
19+
type: 'tendermint/PubKeySecp256k1',
20+
value: base64String,
21+
},
22+
ADDRESS_PREFIX
23+
);
1524
}
1625
}

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,34 @@
11
import { CosmosUtils } from '@bitgo/abstract-cosmos';
2+
import { InvalidTransactionError } from '@bitgo/sdk-core';
23
import { Coin } from '@cosmjs/stargate';
4+
import BigNumber from 'bignumber.js';
5+
import * as constants from './constants';
36

47
export class Utils extends CosmosUtils {
58
/** @inheritdoc */
69
isValidAddress(address: string): boolean {
7-
throw new Error('Method not implemented.');
10+
return this.isValidCosmosLikeAddressWithMemoId(address, constants.accountAddressRegex);
811
}
912

1013
/** @inheritdoc */
1114
isValidValidatorAddress(address: string): boolean {
12-
throw new Error('Method not implemented.');
15+
return this.isValidBech32AddressMatchingRegex(address, constants.validatorAddressRegex);
1316
}
1417

1518
/** @inheritdoc */
1619
isValidContractAddress(address: string): boolean {
17-
throw new Error('Method not implemented.');
20+
return this.isValidBech32AddressMatchingRegex(address, constants.contractAddressRegex);
1821
}
1922

2023
/** @inheritdoc */
2124
validateAmount(amount: Coin): void {
22-
throw new Error('Method not implemented.');
25+
const amountBig = BigNumber(amount.amount);
26+
if (amountBig.isLessThanOrEqualTo(0)) {
27+
throw new InvalidTransactionError('transactionBuilder: validateAmount: Invalid amount: ' + amount.amount);
28+
}
29+
if (!constants.validDenoms.find((denom) => denom === amount.denom)) {
30+
throw new InvalidTransactionError('transactionBuilder: validateAmount: Invalid denom: ' + amount.denom);
31+
}
2332
}
2433
}
2534

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
export const TEST_ACCOUNT = {
2+
pubAddress: 'init1w69e958w8922j3q07pc99338gw547wepu76ygk',
3+
compressedPublicKey: '02bcdbd054a73aa6097c1926c87eb7d66142d2ea710584c4b3e9844e1dab1538f0',
4+
compressedPublicKeyTwo: '02001fda4568760a99e58ee295b4a51edcc6a689297a71f7d1571cf4e1253abcde',
5+
uncompressedPublicKey:
6+
'04bcdbd054a73aa6097c1926c87eb7d66142d2ea710584c4b3e9844e1dab1538f0a088291e83cb3438431deb5e251439e338d8edc4389ea2004f442a73cc97afc8',
7+
privateKey: '3f020639e98e5c4953abb23d01a7c892e83b57593a7f46f37298b58cbf1cacd5',
8+
extendedPrv:
9+
'xprv9s21ZrQH143K3n6kDURwkfkBxB58Fxoz7cFCbpQeFws4K5iXaSUcpq18cCqJQ74MnqNrnLBHfE7YvUgKpnckmpsBLExGSRK55Ud5uuxGrxL',
10+
extendedPub:
11+
'xpub661MyMwAqRbcGGBDKVxx7ogvWCucfRXqUqAoQCpFpHQ3Bt3g7ynsNdKcTWvGGYrpq6VYPPgxjMfKaszXMhKmmCZEnhg9RpqcGeP9uCnZsD9',
12+
};
13+
14+
export const TEST_SEND_TX = {
15+
hash: 'A7AB5F0273AEB21D8589E9CE0CAD88E597F7429915234E925921E30EC72E04E6',
16+
signature: 'UnSmSuU+Q5f2PbuYUI8CBuBKpugCNfR5C/WyGIl5tpYjMsxhpcH503UN8bRRVRy0+IZMaWtqkP1d5mKMQ4ox4w==',
17+
pubKey: 'Aq6esFYEASosOy+P8oL8Qa6YEgw5Ik7+ImI4yaGajBuu',
18+
privateKey: 'HsNHJw6QAHsAO65PkX8O3m6H7Dkddv/KMpfkkL75doE=',
19+
signedTxBase64:
20+
'Co0BCooBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmoKK2luaXQxdzY5ZTk1OHc4OTIyajNxMDdwYzk5MzM4Z3c1NDd3ZXB1NzZ5Z2sSK2luaXQxcjRreXVqN3A5ZG0yeDJxaDR2ZXM4cm10anhsajc3cTZscTYwcHQaDgoFdWluaXQSBTEwMDAwEmgKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQKunrBWBAEqLDsvj/KC/EGumBIMOSJO/iJiOMmhmowbrhIECgIIARgLEhQKDgoFdWluaXQSBTMwMDAwEKDCHhpAUnSmSuU+Q5f2PbuYUI8CBuBKpugCNfR5C/WyGIl5tpYjMsxhpcH503UN8bRRVRy0+IZMaWtqkP1d5mKMQ4ox4w==',
21+
sender: 'init1w69e958w8922j3q07pc99338gw547wepu76ygk',
22+
recipient: 'init1r4kyuj7p9dm2x2qh4ves8rmtjxlj77q6lq60pt',
23+
chainId: 'initiation-2',
24+
accountNumber: 11,
25+
sequence: 11,
26+
sendAmount: '10000',
27+
feeAmount: '30000',
28+
sendMessage: {
29+
typeUrl: '/cosmos.bank.v1beta1.MsgSend',
30+
value: {
31+
amount: [
32+
{
33+
denom: 'uinit',
34+
amount: '10000',
35+
},
36+
],
37+
toAddress: 'init1r4kyuj7p9dm2x2qh4ves8rmtjxlj77q6lq60pt',
38+
fromAddress: 'init1w69e958w8922j3q07pc99338gw547wepu76ygk',
39+
},
40+
},
41+
gasBudget: {
42+
amount: [{ denom: 'uinit', amount: '30000' }],
43+
gasLimit: 500000,
44+
},
45+
};
46+
47+
export const TEST_SEND_TX2 = {
48+
hash: 'A80DC6BB5C6CA0A02CF54F58B307AC0230C33AF9347F0A1CB639B4C142458CD9',
49+
signature: 'Cz24QQpt2xaQ18pfOiYtp2EZDfV9zka6YYkaHX44stUiDKZ6hLMleF46nj2x+GT7CJUnn4pdtOoJfTaPW/tbnQ==',
50+
pubKey: 'Aq6esFYEASosOy+P8oL8Qa6YEgw5Ik7+ImI4yaGajBuu',
51+
privateKey: 'HsNHJw6QAHsAO65PkX8O3m6H7Dkddv/KMpfkkL75doE=',
52+
signedTxBase64:
53+
'Co0BCooBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmoKK2luaXQxdzY5ZTk1OHc4OTIyajNxMDdwYzk5MzM4Z3c1NDd3ZXB1NzZ5Z2sSK2luaXQxcjRreXVqN3A5ZG0yeDJxaDR2ZXM4cm10anhsajc3cTZscTYwcHQaDgoFdWluaXQSBTMwMDAwEmgKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQKunrBWBAEqLDsvj/KC/EGumBIMOSJO/iJiOMmhmowbrhIECgIIARgMEhQKDgoFdWluaXQSBTMwMDAwEKDCHhpACz24QQpt2xaQ18pfOiYtp2EZDfV9zka6YYkaHX44stUiDKZ6hLMleF46nj2x+GT7CJUnn4pdtOoJfTaPW/tbnQ==',
54+
sender: 'init1w69e958w8922j3q07pc99338gw547wepu76ygk',
55+
recipient: 'init1r4kyuj7p9dm2x2qh4ves8rmtjxlj77q6lq60pt',
56+
chainId: 'initiation-2',
57+
accountNumber: 12,
58+
sequence: 12,
59+
sendAmount: '30000',
60+
feeAmount: '30000',
61+
sendMessage: {
62+
typeUrl: '/cosmos.bank.v1beta1.MsgSend',
63+
value: {
64+
amount: [
65+
{
66+
denom: 'uinit',
67+
amount: '30000',
68+
},
69+
],
70+
toAddress: 'init1r4kyuj7p9dm2x2qh4ves8rmtjxlj77q6lq60pt',
71+
fromAddress: 'init1w69e958w8922j3q07pc99338gw547wepu76ygk',
72+
},
73+
},
74+
gasBudget: {
75+
amount: [{ denom: 'uinit', amount: '30000' }],
76+
gasLimit: 500000,
77+
},
78+
};
79+
80+
export const TEST_SEND_MANY_TX = {
81+
hash: 'C08126CEC4F6C4907A8B52BC879B0BBA28E7FC2FCBBFCB1331EC17CB7A4C7CD0',
82+
signature: 'lDLRazFhpE6DBCPSAQyeL37MVHRBTwCVO7Pj7Wx+xCxGFdlc5MSY/w0PyFC8kmRtCIRgnvPBTc+gCGfvX3wlDQ==',
83+
pubKey: 'Aq6esFYEASosOy+P8oL8Qa6YEgw5Ik7+ImI4yaGajBuu',
84+
privateKey: 'HsNHJw6QAHsAO65PkX8O3m6H7Dkddv/KMpfkkL75doE=',
85+
signedTxBase64:
86+
'CpoCCooBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmoKK2luaXQxdzY5ZTk1OHc4OTIyajNxMDdwYzk5MzM4Z3c1NDd3ZXB1NzZ5Z2sSK2luaXQxcjRreXVqN3A5ZG0yeDJxaDR2ZXM4cm10anhsajc3cTZscTYwcHQaDgoFdWluaXQSBTEwMDAwCooBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmoKK2luaXQxdzY5ZTk1OHc4OTIyajNxMDdwYzk5MzM4Z3c1NDd3ZXB1NzZ5Z2sSK2luaXQxN3hwZnZha20yYW1nOTYyeWxzNmY4NHoza2VsbDhjNWw3MHJucWwaDgoFdWluaXQSBTEwMDAwEmgKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQKunrBWBAEqLDsvj/KC/EGumBIMOSJO/iJiOMmhmowbrhIECgIIARgGEhQKDgoFdWluaXQSBTMwMDAwEKDCHhpAlDLRazFhpE6DBCPSAQyeL37MVHRBTwCVO7Pj7Wx+xCxGFdlc5MSY/w0PyFC8kmRtCIRgnvPBTc+gCGfvX3wlDQ==',
87+
sender: 'init1w69e958w8922j3q07pc99338gw547wepu76ygk',
88+
chainId: 'initiation-2',
89+
accountNumber: 6,
90+
sequence: 6,
91+
memo: '',
92+
sendMessages: [
93+
{
94+
typeUrl: '/cosmos.bank.v1beta1.MsgSend',
95+
value: {
96+
amount: [
97+
{
98+
denom: 'uinit',
99+
amount: '10000',
100+
},
101+
],
102+
toAddress: 'init1r4kyuj7p9dm2x2qh4ves8rmtjxlj77q6lq60pt',
103+
fromAddress: 'init1w69e958w8922j3q07pc99338gw547wepu76ygk',
104+
},
105+
},
106+
{
107+
typeUrl: '/cosmos.bank.v1beta1.MsgSend',
108+
value: {
109+
amount: [
110+
{
111+
denom: 'uinit',
112+
amount: '10000',
113+
},
114+
],
115+
toAddress: 'init17xpfvakm2amg962yls6f84z3kell8c5l70rnql',
116+
fromAddress: 'init1w69e958w8922j3q07pc99338gw547wepu76ygk',
117+
},
118+
},
119+
],
120+
gasBudget: {
121+
amount: [{ denom: 'uinit', amount: '30000' }],
122+
gasLimit: 500000,
123+
},
124+
};
125+
126+
export const TEST_TX_WITH_MEMO = {
127+
hash: '1448E3DA45FAA2E2E15AEAF55DCCF54A555F187C233F38E2B04CFA756C82003C',
128+
signature: 'ifZYlCQuBiw8zcyYIq2BxVdzL0BJThmKV02Pzg7E85dDONHjKKknrvn5yw9Z/V++3SfAi+AwnCsopvf9Is7qHw==',
129+
pubKey: 'Aq6esFYEASosOy+P8oL8Qa6YEgw5Ik7+ImI4yaGajBuu',
130+
privateKey: 'HsNHJw6QAHsAO65PkX8O3m6H7Dkddv/KMpfkkL75doE=',
131+
signedTxBase64:
132+
'CpIBCooBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmoKK2luaXQxdzY5ZTk1OHc4OTIyajNxMDdwYzk5MzM4Z3c1NDd3ZXB1NzZ5Z2sSK2luaXQxcjRreXVqN3A5ZG0yeDJxaDR2ZXM4cm10anhsajc3cTZscTYwcHQaDgoFdWluaXQSBTMwMDAwEgMyNDESaApQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAq6esFYEASosOy+P8oL8Qa6YEgw5Ik7+ImI4yaGajBuuEgQKAggBGAoSFAoOCgV1aW5pdBIFMzAwMDAQoMIeGkCJ9liUJC4GLDzNzJgirYHFV3MvQElOGYpXTY/ODsTzl0M40eMoqSeu+fnLD1n9X77dJ8CL4DCcKyim9/0izuof',
133+
from: 'init1w69e958w8922j3q07pc99338gw547wepu76ygk',
134+
to: 'init1r4kyuj7p9dm2x2qh4ves8rmtjxlj77q6lq60pt',
135+
chainId: 'initiation-2',
136+
accountNumber: 10,
137+
sequence: 10,
138+
feeAmount: '30000',
139+
sendAmount: '30000',
140+
sendMessage: {
141+
typeUrl: '/cosmos.bank.v1beta1.MsgSend',
142+
value: {
143+
amount: [
144+
{
145+
denom: 'uinit',
146+
amount: '30000',
147+
},
148+
],
149+
fromAddress: 'init1w69e958w8922j3q07pc99338gw547wepu76ygk',
150+
toAddress: 'init1r4kyuj7p9dm2x2qh4ves8rmtjxlj77q6lq60pt',
151+
},
152+
},
153+
memo: '241',
154+
gasBudget: {
155+
amount: [{ denom: 'uinit', amount: '30000' }],
156+
gasLimit: 500000,
157+
},
158+
};
159+
160+
export const address = {
161+
address1: 'init1w69e958w8922j3q07pc99338gw547wepu76ygk',
162+
address2: 'init1r4kyuj7p9dm2x2qh4ves8rmtjxlj77q6lq60pt',
163+
address3: 'init1r4kyujp9dm2x2qh4,ves87rmtjxlj77q6lq60pt-yf2',
164+
address4: 'inict17xpfvakm2amg962yls6f84z3kell85l70rnql',
165+
address5: 'init17xpfvakm2amg962yls6f84z3kell8c5l70rnql1',
166+
address6: 'init17xpfvakm2amg962yls6f84z3kell8c5l70rnql.9pvdadzax7durfm7hlfn8',
167+
validatorAddress1: 'initvaloper13xnlyk0uz3ccfvsfvv8q36p7exvphferkusz0h',
168+
validatorAddress2: 'initvaloper1lcrpklc7yhl5v8kg2feedweqg3cpw005eq39w3',
169+
validatorAddress3: 'initvalper1qx6ghyv83caecuxgl77lvlndha9d9y6fntryc8a#d46w',
170+
validatorAddress4: 'initvaloper1qx6ghyv83caecuxgl77lvlnha9d9ys6fntryc8a',
171+
noMemoIdAddress: 'init1r4kyuj7p9dm2x2qh4ves8rmtjxlj77q6lq60pt',
172+
validMemoIdAddress: 'init1r4kyuj7p9dm2x2qh4ves8rmtjxlj77q6lq60pt?memoId=2',
173+
invalidMemoIdAddress: 'init1r4kyuj7p9dm2x2qh4ves8rmtjxlj77q6lq60pt?memoId=1.23',
174+
multipleMemoIdAddress: 'init1r4kyuj7p9dm2x2qh4ves8rmtjxlj77q6lq60pt?memoId=3&memoId=12',
175+
};
176+
177+
export const blockHash = {
178+
hash1: '25E7C3989DDE06BBCCEBDFBA7A0AA38CF05EF14C3FBCE8A4B4349FCB5863F189',
179+
hash2: '8CBEA52AA9937916264C303E121E08BF2C35C85810ECC2B76E76FC982CC6ABF8',
180+
};
181+
182+
export const txIds = {
183+
hash1: '02D8E9AC3F33D6825F8F13E494EF6B0E035160DBAA82865666EAEC095FF36156',
184+
hash2: 'A7AB5F0273AEB21D8589E9CE0CAD88E597F7429915234E925921E30EC72E04E6',
185+
hash3: 'A80DC6BB5C6CA0A02CF54F58B307AC0230C33AF9347F0A1CB639B4C142458CD9',
186+
};
187+
188+
export const coinAmounts = {
189+
amount1: { amount: '100000', denom: 'uinit' },
190+
amount2: { amount: '1000000', denom: 'uinit' },
191+
amount3: { amount: '10000000', denom: 'uinit' },
192+
amount4: { amount: '-1', denom: 'uinit' },
193+
amount5: { amount: '1000000000', denom: 'muinit' },
194+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { TransactionBuilderFactory } from '../../src';
2+
import { coins } from '@bitgo/statics';
3+
4+
export const getBuilderFactory = (coin: string): TransactionBuilderFactory => {
5+
return new TransactionBuilderFactory(coins.get(coin));
6+
};

0 commit comments

Comments
 (0)