@xchainjs/xchain-thorchain 0.20.0 → 0.21.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,50 @@
1
+ # v0.21.2 (2022-02-04)
2
+
3
+ ## Fix
4
+
5
+ - Use latest axios@0.25.0
6
+ - xchain-client@0.11.1
7
+ - @xchainjs/xchain-util@0.5.1
8
+ - @xchainjs/xchain-cosmos@0.16.1
9
+
10
+ # v.0.21.1 (2022-02-04)
11
+
12
+ ## Fix
13
+
14
+ - Fix chain id for `testnet` #477
15
+
16
+ ## Add
17
+
18
+ - Helper `isChainId`
19
+ - `enum ChainId`
20
+
21
+ # v.0.21.0 (2022-02-02)
22
+
23
+ ## Breaking change
24
+
25
+ - Remove `getDenomWithChain`
26
+ - Rename `getAsset` -> `assetFromDenom` (incl. fix to get synth asset properly)
27
+
28
+ ## Update
29
+
30
+ - xchain-util@0.5.0
31
+ - xchain-cosmos@0.16.0
32
+
33
+ ## Add
34
+
35
+ - `isAssetNativeRune` helper
36
+ - Add `TxOfflineParams` type
37
+
38
+ ## Fix
39
+
40
+ - Fix synth notation in `transfer|transferOffline|deposit` #473
41
+
42
+ # v0.20.1 (2022-01-11)
43
+
44
+ ## Fix
45
+
46
+ - Get chain ID from THORNode before posting to deposit handler.
47
+
1
48
  # v.0.20.0 (2021-12-29)
2
49
 
3
50
  ## Breaking change
package/lib/client.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { Address, Balance, Fees, Network, Tx, TxHash, TxHistoryParams, TxParams, TxsPage, XChainClient, XChainClientParams } from '@xchainjs/xchain-client';
2
- import { CosmosSDKClient, RPCTxResult, TxOfflineParams } from '@xchainjs/xchain-cosmos';
2
+ import { CosmosSDKClient, RPCTxResult } from '@xchainjs/xchain-cosmos';
3
3
  import { Asset } from '@xchainjs/xchain-util';
4
4
  import { PrivKey, PubKey } from 'cosmos-client';
5
5
  import { StdTx } from 'cosmos-client/x/auth';
6
- import { ClientUrl, DepositParam, ExplorerUrls, NodeUrl, ThorchainClientParams } from './types';
6
+ import { ClientUrl, DepositParam, ExplorerUrls, NodeUrl, ThorchainClientParams, TxOfflineParams } from './types';
7
7
  /**
8
8
  * Interface for custom Thorchain client
9
9
  */
@@ -212,7 +212,7 @@ declare class Client implements ThorchainClient, XChainClient {
212
212
  * @param {TxOfflineParams} params The transfer offline options.
213
213
  * @returns {StdTx} The signed transaction.
214
214
  */
215
- transferOffline({ walletIndex, asset, amount, recipient, memo, from_balance, from_account_number, from_sequence, }: TxOfflineParams): Promise<StdTx>;
215
+ transferOffline({ walletIndex, asset, amount, recipient, memo, from_rune_balance, from_asset_balance, from_account_number, from_sequence, }: TxOfflineParams): Promise<StdTx>;
216
216
  /**
217
217
  * Get the fees.
218
218
  *
package/lib/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
- import { Network, TxType, singleFee, FeeType, FeeOption } from '@xchainjs/xchain-client';
1
+ import { Network, TxType, singleFee, FeeType } from '@xchainjs/xchain-client';
2
2
  import { CosmosSDKClient } from '@xchainjs/xchain-cosmos';
3
3
  import { validatePhrase } from '@xchainjs/xchain-crypto';
4
- import { assetToString, AssetRuneNative, Chain, assetFromString, baseAmount } from '@xchainjs/xchain-util';
4
+ import { assetToString, AssetRuneNative, isSynthAsset, assetFromString, baseAmount } from '@xchainjs/xchain-util';
5
5
  import axios from 'axios';
6
6
  import { AccAddress, Msg, codec } from 'cosmos-client';
7
7
  import { StdTx } from 'cosmos-client/x/auth';
@@ -119,24 +119,25 @@ var DEFAULT_GAS_VALUE = '2000000';
119
119
  var DEPOSIT_GAS_VALUE = '500000000';
120
120
  var MAX_TX_COUNT = 100;
121
121
  /**
122
- * Get denomination from Asset
122
+ * Checks whether an asset is `AssetRuneNative`
123
123
  *
124
124
  * @param {Asset} asset
125
- * @returns {string} The denomination of the given asset.
125
+ * @returns {boolean} `true` or `false`
126
126
  */
127
- var getDenom = function (asset) {
128
- if (assetToString(asset) === assetToString(AssetRuneNative))
129
- return 'rune';
130
- return asset.symbol;
131
- };
127
+ var isAssetRuneNative = function (asset) { return assetToString(asset) === assetToString(AssetRuneNative); };
128
+ var DENOM_RUNE_NATIVE = 'rune';
132
129
  /**
133
- * Get denomination with chainname from Asset
130
+ * Get denomination from Asset
134
131
  *
135
132
  * @param {Asset} asset
136
- * @returns {string} The denomination with chainname of the given asset.
133
+ * @returns {string} The denomination of the given asset.
137
134
  */
138
- var getDenomWithChain = function (asset) {
139
- return Chain.THORChain + "." + asset.symbol.toUpperCase();
135
+ var getDenom = function (asset) {
136
+ if (isAssetRuneNative(asset))
137
+ return DENOM_RUNE_NATIVE;
138
+ if (isSynthAsset(asset))
139
+ return assetToString(asset).toLowerCase();
140
+ return asset.symbol.toLowerCase();
140
141
  };
141
142
  /**
142
143
  * Get Asset from denomination
@@ -144,10 +145,10 @@ var getDenomWithChain = function (asset) {
144
145
  * @param {string} denom
145
146
  * @returns {Asset|null} The asset of the given denomination.
146
147
  */
147
- var getAsset = function (denom) {
148
- if (denom === getDenom(AssetRuneNative))
148
+ var assetFromDenom = function (denom) {
149
+ if (denom === DENOM_RUNE_NATIVE)
149
150
  return AssetRuneNative;
150
- return assetFromString(Chain.THORChain + "." + denom.toUpperCase());
151
+ return assetFromString(denom.toUpperCase());
151
152
  };
152
153
  /**
153
154
  * Type guard for MsgSend
@@ -197,12 +198,36 @@ var getPrefix = function (network) {
197
198
  return 'tthor';
198
199
  }
199
200
  };
201
+ var ChainId;
202
+ (function (ChainId) {
203
+ ChainId["Mainnet"] = "thorchain";
204
+ ChainId["Stagenet"] = "thorchain-stagenet";
205
+ ChainId["Testnet"] = "thorchain-v1";
206
+ })(ChainId || (ChainId = {}));
207
+ /**
208
+ * Type guard to check whether string is a valid `ChainId`
209
+ *
210
+ * @param {string} id Chain id.
211
+ * @returns {boolean} `true` or `false`
212
+ */
213
+ var isChainId = function (id) { return Object.values(ChainId).includes(id); };
200
214
  /**
201
215
  * Get the chain id.
202
216
  *
217
+ * @param {Network} network
203
218
  * @returns {string} The chain id based on the network.
219
+ *
204
220
  */
205
- var getChainId = function () { return 'thorchain'; };
221
+ var getChainId = function (network) {
222
+ switch (network) {
223
+ case Network.Mainnet:
224
+ return ChainId.Mainnet;
225
+ case Network.Stagenet:
226
+ return ChainId.Stagenet;
227
+ case Network.Testnet:
228
+ return ChainId.Testnet;
229
+ }
230
+ };
206
231
  /**
207
232
  * Register Codecs based on the prefix.
208
233
  *
@@ -286,19 +311,25 @@ var getTxType = function (txData, encoding) {
286
311
  * @throws {"Invalid client url"} Thrown if the client url is an invalid one.
287
312
  */
288
313
  var buildDepositTx = function (msgNativeTx, nodeUrl) { return __awaiter(void 0, void 0, void 0, function () {
289
- var response, fee, unsignedStdTx;
314
+ var data, chainId, response, fee, unsignedStdTx;
290
315
  var _a, _b;
291
316
  return __generator(this, function (_c) {
292
317
  switch (_c.label) {
293
- case 0: return [4 /*yield*/, axios.post(nodeUrl + "/thorchain/deposit", {
294
- coins: msgNativeTx.coins,
295
- memo: msgNativeTx.memo,
296
- base_req: {
297
- chain_id: getChainId(),
298
- from: msgNativeTx.signer,
299
- },
300
- })];
318
+ case 0: return [4 /*yield*/, axios.get(nodeUrl + "/cosmos/base/tendermint/v1beta1/node_info")];
301
319
  case 1:
320
+ data = (_c.sent()).data;
321
+ chainId = data.default_node_info.network;
322
+ if (!chainId || !isChainId(chainId))
323
+ throw new Error('invalid network');
324
+ return [4 /*yield*/, axios.post(nodeUrl + "/thorchain/deposit", {
325
+ coins: msgNativeTx.coins,
326
+ memo: msgNativeTx.memo,
327
+ base_req: {
328
+ chain_id: chainId,
329
+ from: msgNativeTx.signer,
330
+ },
331
+ })];
332
+ case 2:
302
333
  response = (_c.sent()).data;
303
334
  if (!response || !response.value)
304
335
  throw new Error('Invalid client url');
@@ -334,7 +365,7 @@ var getBalance = function (_a) {
334
365
  balances = _b.sent();
335
366
  return [2 /*return*/, balances
336
367
  .map(function (balance) { return ({
337
- asset: (balance.denom && getAsset(balance.denom)) || AssetRuneNative,
368
+ asset: (balance.denom && assetFromDenom(balance.denom)) || AssetRuneNative,
338
369
  amount: baseAmount(balance.amount, DECIMAL),
339
370
  }); })
340
371
  .filter(function (balance) { return !assets || assets.filter(function (asset) { return assetToString(balance.asset) === assetToString(asset); }).length; })];
@@ -541,7 +572,7 @@ var Client = /** @class */ (function () {
541
572
  this.rootDerivationPaths = rootDerivationPaths;
542
573
  this.cosmosClient = new CosmosSDKClient({
543
574
  server: this.getClientUrl().node,
544
- chainId: getChainId(),
575
+ chainId: getChainId(this.network),
545
576
  prefix: getPrefix(this.network),
546
577
  });
547
578
  if (phrase)
@@ -813,23 +844,41 @@ var Client = /** @class */ (function () {
813
844
  * @throws {"failed to broadcast transaction"} Thrown if failed to broadcast transaction.
814
845
  */
815
846
  Client.prototype.deposit = function (_a) {
816
- var _b, _c;
817
- var _d = _a.walletIndex, walletIndex = _d === void 0 ? 0 : _d, _e = _a.asset, asset = _e === void 0 ? AssetRuneNative : _e, amount = _a.amount, memo = _a.memo;
847
+ var _b, _c, _d, _e, _f, _g;
848
+ var _h = _a.walletIndex, walletIndex = _h === void 0 ? 0 : _h, _j = _a.asset, asset = _j === void 0 ? AssetRuneNative : _j, amount = _a.amount, memo = _a.memo;
818
849
  return __awaiter(this, void 0, void 0, function () {
819
- var assetBalance, signer, msgNativeTx, unsignedStdTx, privateKey, accAddress;
820
- return __generator(this, function (_f) {
821
- switch (_f.label) {
822
- case 0: return [4 /*yield*/, this.getBalance(this.getAddress(walletIndex), [asset])];
850
+ var balances, runeBalance, assetBalance, fee, signer, msgNativeTx, unsignedStdTx, privateKey, accAddress;
851
+ return __generator(this, function (_k) {
852
+ switch (_k.label) {
853
+ case 0: return [4 /*yield*/, this.getBalance(this.getAddress(walletIndex))];
823
854
  case 1:
824
- assetBalance = _f.sent();
825
- if (assetBalance.length === 0 || assetBalance[0].amount.amount().lt(amount.amount().plus(DEFAULT_GAS_VALUE))) {
826
- throw new Error('insufficient funds');
855
+ balances = _k.sent();
856
+ runeBalance = (_c = (_b = balances.filter(function (_a) {
857
+ var asset = _a.asset;
858
+ return isAssetRuneNative(asset);
859
+ })[0]) === null || _b === void 0 ? void 0 : _b.amount) !== null && _c !== void 0 ? _c : baseAmount(0, DECIMAL);
860
+ assetBalance = (_e = (_d = balances.filter(function (_a) {
861
+ var assetInList = _a.asset;
862
+ return assetToString(assetInList) === assetToString(asset);
863
+ })[0]) === null || _d === void 0 ? void 0 : _d.amount) !== null && _e !== void 0 ? _e : baseAmount(0, DECIMAL);
864
+ fee = baseAmount(DEFAULT_GAS_VALUE, DECIMAL);
865
+ if (isAssetRuneNative(asset)) {
866
+ // amount + fee < runeBalance
867
+ if (runeBalance.lt(amount.plus(fee))) {
868
+ throw new Error('insufficient funds');
869
+ }
870
+ }
871
+ else {
872
+ // amount < assetBalances && runeBalance < fee
873
+ if (assetBalance.lt(amount) || runeBalance.lt(fee)) {
874
+ throw new Error('insufficient funds');
875
+ }
827
876
  }
828
877
  signer = this.getAddress(walletIndex);
829
878
  msgNativeTx = msgNativeTxFromJson({
830
879
  coins: [
831
880
  {
832
- asset: getDenomWithChain(asset),
881
+ asset: isAssetRuneNative(asset) ? assetToString(AssetRuneNative) : getDenom(asset),
833
882
  amount: amount.amount().toString(),
834
883
  },
835
884
  ],
@@ -838,11 +887,11 @@ var Client = /** @class */ (function () {
838
887
  });
839
888
  return [4 /*yield*/, buildDepositTx(msgNativeTx, this.getClientUrl().node)];
840
889
  case 2:
841
- unsignedStdTx = _f.sent();
890
+ unsignedStdTx = _k.sent();
842
891
  privateKey = this.getPrivKey(walletIndex);
843
892
  accAddress = AccAddress.fromBech32(signer);
844
893
  return [4 /*yield*/, this.cosmosClient.signAndBroadcast(unsignedStdTx, privateKey, accAddress)];
845
- case 3: return [2 /*return*/, (_c = (_b = (_f.sent())) === null || _b === void 0 ? void 0 : _b.txhash) !== null && _c !== void 0 ? _c : ''];
894
+ case 3: return [2 /*return*/, (_g = (_f = (_k.sent())) === null || _f === void 0 ? void 0 : _f.txhash) !== null && _g !== void 0 ? _g : ''];
846
895
  }
847
896
  });
848
897
  });
@@ -854,22 +903,39 @@ var Client = /** @class */ (function () {
854
903
  * @returns {TxHash} The transaction hash.
855
904
  */
856
905
  Client.prototype.transfer = function (_a) {
857
- var _b = _a.walletIndex, walletIndex = _b === void 0 ? 0 : _b, _c = _a.asset, asset = _c === void 0 ? AssetRuneNative : _c, amount = _a.amount, recipient = _a.recipient, memo = _a.memo;
906
+ var _b, _c, _d, _e;
907
+ var _f = _a.walletIndex, walletIndex = _f === void 0 ? 0 : _f, _g = _a.asset, asset = _g === void 0 ? AssetRuneNative : _g, amount = _a.amount, recipient = _a.recipient, memo = _a.memo;
858
908
  return __awaiter(this, void 0, void 0, function () {
859
- var assetBalance, fee, transferResult;
860
- return __generator(this, function (_d) {
861
- switch (_d.label) {
909
+ var balances, runeBalance, assetBalance, fee, transferResult;
910
+ return __generator(this, function (_h) {
911
+ switch (_h.label) {
862
912
  case 0:
863
913
  registerCodecs(getPrefix(this.network));
864
- return [4 /*yield*/, this.getBalance(this.getAddress(walletIndex), [asset])];
914
+ return [4 /*yield*/, this.getBalance(this.getAddress(walletIndex))];
865
915
  case 1:
866
- assetBalance = _d.sent();
916
+ balances = _h.sent();
917
+ runeBalance = (_c = (_b = balances.filter(function (_a) {
918
+ var asset = _a.asset;
919
+ return isAssetRuneNative(asset);
920
+ })[0]) === null || _b === void 0 ? void 0 : _b.amount) !== null && _c !== void 0 ? _c : baseAmount(0, DECIMAL);
921
+ assetBalance = (_e = (_d = balances.filter(function (_a) {
922
+ var assetInList = _a.asset;
923
+ return assetToString(assetInList) === assetToString(asset);
924
+ })[0]) === null || _d === void 0 ? void 0 : _d.amount) !== null && _e !== void 0 ? _e : baseAmount(0, DECIMAL);
867
925
  return [4 /*yield*/, this.getFees()];
868
926
  case 2:
869
- fee = _d.sent();
870
- if (assetBalance.length === 0 ||
871
- assetBalance[0].amount.amount().lt(amount.amount().plus(fee[FeeOption.Average].amount()))) {
872
- throw new Error('insufficient funds');
927
+ fee = (_h.sent()).average;
928
+ if (isAssetRuneNative(asset)) {
929
+ // amount + fee < runeBalance
930
+ if (runeBalance.lt(amount.plus(fee))) {
931
+ throw new Error('insufficient funds');
932
+ }
933
+ }
934
+ else {
935
+ // amount < assetBalances && runeBalance < fee
936
+ if (assetBalance.lt(amount) || runeBalance.lt(fee)) {
937
+ throw new Error('insufficient funds');
938
+ }
873
939
  }
874
940
  return [4 /*yield*/, this.cosmosClient.transfer({
875
941
  privkey: this.getPrivKey(walletIndex),
@@ -884,7 +950,7 @@ var Client = /** @class */ (function () {
884
950
  },
885
951
  })];
886
952
  case 3:
887
- transferResult = _d.sent();
953
+ transferResult = _h.sent();
888
954
  if (!isBroadcastSuccess(transferResult)) {
889
955
  throw new Error("failed to broadcast transaction: " + transferResult.txhash);
890
956
  }
@@ -900,7 +966,7 @@ var Client = /** @class */ (function () {
900
966
  * @returns {StdTx} The signed transaction.
901
967
  */
902
968
  Client.prototype.transferOffline = function (_a) {
903
- var _b = _a.walletIndex, walletIndex = _b === void 0 ? 0 : _b, _c = _a.asset, asset = _c === void 0 ? AssetRuneNative : _c, amount = _a.amount, recipient = _a.recipient, memo = _a.memo, _d = _a.from_balance, from_balance = _d === void 0 ? baseAmount('0', DECIMAL) : _d, _e = _a.from_account_number, from_account_number = _e === void 0 ? '0' : _e, _f = _a.from_sequence, from_sequence = _f === void 0 ? '0' : _f;
969
+ var _b = _a.walletIndex, walletIndex = _b === void 0 ? 0 : _b, _c = _a.asset, asset = _c === void 0 ? AssetRuneNative : _c, amount = _a.amount, recipient = _a.recipient, memo = _a.memo, from_rune_balance = _a.from_rune_balance, _d = _a.from_asset_balance, from_asset_balance = _d === void 0 ? baseAmount(0, DECIMAL) : _d, _e = _a.from_account_number, from_account_number = _e === void 0 ? '0' : _e, _f = _a.from_sequence, from_sequence = _f === void 0 ? '0' : _f;
904
970
  return __awaiter(this, void 0, void 0, function () {
905
971
  var fee, result;
906
972
  return __generator(this, function (_g) {
@@ -909,10 +975,18 @@ var Client = /** @class */ (function () {
909
975
  registerCodecs(getPrefix(this.network));
910
976
  return [4 /*yield*/, this.getFees()];
911
977
  case 1:
912
- fee = _g.sent();
913
- if (from_balance === baseAmount('0', DECIMAL) ||
914
- from_balance.amount().lt(amount.amount().plus(fee[FeeOption.Average].amount()))) {
915
- throw new Error('insufficient funds');
978
+ fee = (_g.sent()).average;
979
+ if (isAssetRuneNative(asset)) {
980
+ // amount + fee < runeBalance
981
+ if (from_rune_balance.lt(amount.plus(fee))) {
982
+ throw new Error('insufficient funds');
983
+ }
984
+ }
985
+ else {
986
+ // amount < assetBalances && runeBalance < fee
987
+ if (from_asset_balance.lt(amount) || from_rune_balance.lt(fee)) {
988
+ throw new Error('insufficient funds');
989
+ }
916
990
  }
917
991
  return [4 /*yield*/, this.cosmosClient.transferSignedOffline({
918
992
  privkey: this.getPrivKey(walletIndex),
@@ -950,4 +1024,4 @@ var Client = /** @class */ (function () {
950
1024
  return Client;
951
1025
  }());
952
1026
 
953
- export { Client, DECIMAL, DEFAULT_GAS_VALUE, DEPOSIT_GAS_VALUE, MAX_TX_COUNT, MsgNativeTx, buildDepositTx, getAsset, getBalance, getChainId, getDefaultClientUrl, getDefaultExplorerUrls, getDefaultFees, getDenom, getDenomWithChain, getDepositTxDataFromLogs, getExplorerAddressUrl, getExplorerTxUrl, getExplorerUrl, getPrefix, getTxType, isBroadcastSuccess, isMsgMultiSend, isMsgSend, msgNativeTxFromJson, registerCodecs };
1027
+ export { ChainId, Client, DECIMAL, DEFAULT_GAS_VALUE, DEPOSIT_GAS_VALUE, MAX_TX_COUNT, MsgNativeTx, assetFromDenom, buildDepositTx, getBalance, getChainId, getDefaultClientUrl, getDefaultExplorerUrls, getDefaultFees, getDenom, getDepositTxDataFromLogs, getExplorerAddressUrl, getExplorerTxUrl, getExplorerUrl, getPrefix, getTxType, isAssetRuneNative, isBroadcastSuccess, isChainId, isMsgMultiSend, isMsgSend, msgNativeTxFromJson, registerCodecs };
package/lib/index.js CHANGED
@@ -127,24 +127,25 @@ var DEFAULT_GAS_VALUE = '2000000';
127
127
  var DEPOSIT_GAS_VALUE = '500000000';
128
128
  var MAX_TX_COUNT = 100;
129
129
  /**
130
- * Get denomination from Asset
130
+ * Checks whether an asset is `AssetRuneNative`
131
131
  *
132
132
  * @param {Asset} asset
133
- * @returns {string} The denomination of the given asset.
133
+ * @returns {boolean} `true` or `false`
134
134
  */
135
- var getDenom = function (asset) {
136
- if (xchainUtil.assetToString(asset) === xchainUtil.assetToString(xchainUtil.AssetRuneNative))
137
- return 'rune';
138
- return asset.symbol;
139
- };
135
+ var isAssetRuneNative = function (asset) { return xchainUtil.assetToString(asset) === xchainUtil.assetToString(xchainUtil.AssetRuneNative); };
136
+ var DENOM_RUNE_NATIVE = 'rune';
140
137
  /**
141
- * Get denomination with chainname from Asset
138
+ * Get denomination from Asset
142
139
  *
143
140
  * @param {Asset} asset
144
- * @returns {string} The denomination with chainname of the given asset.
141
+ * @returns {string} The denomination of the given asset.
145
142
  */
146
- var getDenomWithChain = function (asset) {
147
- return xchainUtil.Chain.THORChain + "." + asset.symbol.toUpperCase();
143
+ var getDenom = function (asset) {
144
+ if (isAssetRuneNative(asset))
145
+ return DENOM_RUNE_NATIVE;
146
+ if (xchainUtil.isSynthAsset(asset))
147
+ return xchainUtil.assetToString(asset).toLowerCase();
148
+ return asset.symbol.toLowerCase();
148
149
  };
149
150
  /**
150
151
  * Get Asset from denomination
@@ -152,10 +153,10 @@ var getDenomWithChain = function (asset) {
152
153
  * @param {string} denom
153
154
  * @returns {Asset|null} The asset of the given denomination.
154
155
  */
155
- var getAsset = function (denom) {
156
- if (denom === getDenom(xchainUtil.AssetRuneNative))
156
+ var assetFromDenom = function (denom) {
157
+ if (denom === DENOM_RUNE_NATIVE)
157
158
  return xchainUtil.AssetRuneNative;
158
- return xchainUtil.assetFromString(xchainUtil.Chain.THORChain + "." + denom.toUpperCase());
159
+ return xchainUtil.assetFromString(denom.toUpperCase());
159
160
  };
160
161
  /**
161
162
  * Type guard for MsgSend
@@ -205,12 +206,35 @@ var getPrefix = function (network) {
205
206
  return 'tthor';
206
207
  }
207
208
  };
209
+ (function (ChainId) {
210
+ ChainId["Mainnet"] = "thorchain";
211
+ ChainId["Stagenet"] = "thorchain-stagenet";
212
+ ChainId["Testnet"] = "thorchain-v1";
213
+ })(exports.ChainId || (exports.ChainId = {}));
214
+ /**
215
+ * Type guard to check whether string is a valid `ChainId`
216
+ *
217
+ * @param {string} id Chain id.
218
+ * @returns {boolean} `true` or `false`
219
+ */
220
+ var isChainId = function (id) { return Object.values(exports.ChainId).includes(id); };
208
221
  /**
209
222
  * Get the chain id.
210
223
  *
224
+ * @param {Network} network
211
225
  * @returns {string} The chain id based on the network.
226
+ *
212
227
  */
213
- var getChainId = function () { return 'thorchain'; };
228
+ var getChainId = function (network) {
229
+ switch (network) {
230
+ case xchainClient.Network.Mainnet:
231
+ return exports.ChainId.Mainnet;
232
+ case xchainClient.Network.Stagenet:
233
+ return exports.ChainId.Stagenet;
234
+ case xchainClient.Network.Testnet:
235
+ return exports.ChainId.Testnet;
236
+ }
237
+ };
214
238
  /**
215
239
  * Register Codecs based on the prefix.
216
240
  *
@@ -294,19 +318,25 @@ var getTxType = function (txData, encoding) {
294
318
  * @throws {"Invalid client url"} Thrown if the client url is an invalid one.
295
319
  */
296
320
  var buildDepositTx = function (msgNativeTx, nodeUrl) { return __awaiter(void 0, void 0, void 0, function () {
297
- var response, fee, unsignedStdTx;
321
+ var data, chainId, response, fee, unsignedStdTx;
298
322
  var _a, _b;
299
323
  return __generator(this, function (_c) {
300
324
  switch (_c.label) {
301
- case 0: return [4 /*yield*/, axios__default['default'].post(nodeUrl + "/thorchain/deposit", {
302
- coins: msgNativeTx.coins,
303
- memo: msgNativeTx.memo,
304
- base_req: {
305
- chain_id: getChainId(),
306
- from: msgNativeTx.signer,
307
- },
308
- })];
325
+ case 0: return [4 /*yield*/, axios__default['default'].get(nodeUrl + "/cosmos/base/tendermint/v1beta1/node_info")];
309
326
  case 1:
327
+ data = (_c.sent()).data;
328
+ chainId = data.default_node_info.network;
329
+ if (!chainId || !isChainId(chainId))
330
+ throw new Error('invalid network');
331
+ return [4 /*yield*/, axios__default['default'].post(nodeUrl + "/thorchain/deposit", {
332
+ coins: msgNativeTx.coins,
333
+ memo: msgNativeTx.memo,
334
+ base_req: {
335
+ chain_id: chainId,
336
+ from: msgNativeTx.signer,
337
+ },
338
+ })];
339
+ case 2:
310
340
  response = (_c.sent()).data;
311
341
  if (!response || !response.value)
312
342
  throw new Error('Invalid client url');
@@ -342,7 +372,7 @@ var getBalance = function (_a) {
342
372
  balances = _b.sent();
343
373
  return [2 /*return*/, balances
344
374
  .map(function (balance) { return ({
345
- asset: (balance.denom && getAsset(balance.denom)) || xchainUtil.AssetRuneNative,
375
+ asset: (balance.denom && assetFromDenom(balance.denom)) || xchainUtil.AssetRuneNative,
346
376
  amount: xchainUtil.baseAmount(balance.amount, DECIMAL),
347
377
  }); })
348
378
  .filter(function (balance) { return !assets || assets.filter(function (asset) { return xchainUtil.assetToString(balance.asset) === xchainUtil.assetToString(asset); }).length; })];
@@ -549,7 +579,7 @@ var Client = /** @class */ (function () {
549
579
  this.rootDerivationPaths = rootDerivationPaths;
550
580
  this.cosmosClient = new xchainCosmos.CosmosSDKClient({
551
581
  server: this.getClientUrl().node,
552
- chainId: getChainId(),
582
+ chainId: getChainId(this.network),
553
583
  prefix: getPrefix(this.network),
554
584
  });
555
585
  if (phrase)
@@ -821,23 +851,41 @@ var Client = /** @class */ (function () {
821
851
  * @throws {"failed to broadcast transaction"} Thrown if failed to broadcast transaction.
822
852
  */
823
853
  Client.prototype.deposit = function (_a) {
824
- var _b, _c;
825
- var _d = _a.walletIndex, walletIndex = _d === void 0 ? 0 : _d, _e = _a.asset, asset = _e === void 0 ? xchainUtil.AssetRuneNative : _e, amount = _a.amount, memo = _a.memo;
854
+ var _b, _c, _d, _e, _f, _g;
855
+ var _h = _a.walletIndex, walletIndex = _h === void 0 ? 0 : _h, _j = _a.asset, asset = _j === void 0 ? xchainUtil.AssetRuneNative : _j, amount = _a.amount, memo = _a.memo;
826
856
  return __awaiter(this, void 0, void 0, function () {
827
- var assetBalance, signer, msgNativeTx, unsignedStdTx, privateKey, accAddress;
828
- return __generator(this, function (_f) {
829
- switch (_f.label) {
830
- case 0: return [4 /*yield*/, this.getBalance(this.getAddress(walletIndex), [asset])];
857
+ var balances, runeBalance, assetBalance, fee, signer, msgNativeTx, unsignedStdTx, privateKey, accAddress;
858
+ return __generator(this, function (_k) {
859
+ switch (_k.label) {
860
+ case 0: return [4 /*yield*/, this.getBalance(this.getAddress(walletIndex))];
831
861
  case 1:
832
- assetBalance = _f.sent();
833
- if (assetBalance.length === 0 || assetBalance[0].amount.amount().lt(amount.amount().plus(DEFAULT_GAS_VALUE))) {
834
- throw new Error('insufficient funds');
862
+ balances = _k.sent();
863
+ runeBalance = (_c = (_b = balances.filter(function (_a) {
864
+ var asset = _a.asset;
865
+ return isAssetRuneNative(asset);
866
+ })[0]) === null || _b === void 0 ? void 0 : _b.amount) !== null && _c !== void 0 ? _c : xchainUtil.baseAmount(0, DECIMAL);
867
+ assetBalance = (_e = (_d = balances.filter(function (_a) {
868
+ var assetInList = _a.asset;
869
+ return xchainUtil.assetToString(assetInList) === xchainUtil.assetToString(asset);
870
+ })[0]) === null || _d === void 0 ? void 0 : _d.amount) !== null && _e !== void 0 ? _e : xchainUtil.baseAmount(0, DECIMAL);
871
+ fee = xchainUtil.baseAmount(DEFAULT_GAS_VALUE, DECIMAL);
872
+ if (isAssetRuneNative(asset)) {
873
+ // amount + fee < runeBalance
874
+ if (runeBalance.lt(amount.plus(fee))) {
875
+ throw new Error('insufficient funds');
876
+ }
877
+ }
878
+ else {
879
+ // amount < assetBalances && runeBalance < fee
880
+ if (assetBalance.lt(amount) || runeBalance.lt(fee)) {
881
+ throw new Error('insufficient funds');
882
+ }
835
883
  }
836
884
  signer = this.getAddress(walletIndex);
837
885
  msgNativeTx = msgNativeTxFromJson({
838
886
  coins: [
839
887
  {
840
- asset: getDenomWithChain(asset),
888
+ asset: isAssetRuneNative(asset) ? xchainUtil.assetToString(xchainUtil.AssetRuneNative) : getDenom(asset),
841
889
  amount: amount.amount().toString(),
842
890
  },
843
891
  ],
@@ -846,11 +894,11 @@ var Client = /** @class */ (function () {
846
894
  });
847
895
  return [4 /*yield*/, buildDepositTx(msgNativeTx, this.getClientUrl().node)];
848
896
  case 2:
849
- unsignedStdTx = _f.sent();
897
+ unsignedStdTx = _k.sent();
850
898
  privateKey = this.getPrivKey(walletIndex);
851
899
  accAddress = cosmosClient.AccAddress.fromBech32(signer);
852
900
  return [4 /*yield*/, this.cosmosClient.signAndBroadcast(unsignedStdTx, privateKey, accAddress)];
853
- case 3: return [2 /*return*/, (_c = (_b = (_f.sent())) === null || _b === void 0 ? void 0 : _b.txhash) !== null && _c !== void 0 ? _c : ''];
901
+ case 3: return [2 /*return*/, (_g = (_f = (_k.sent())) === null || _f === void 0 ? void 0 : _f.txhash) !== null && _g !== void 0 ? _g : ''];
854
902
  }
855
903
  });
856
904
  });
@@ -862,22 +910,39 @@ var Client = /** @class */ (function () {
862
910
  * @returns {TxHash} The transaction hash.
863
911
  */
864
912
  Client.prototype.transfer = function (_a) {
865
- var _b = _a.walletIndex, walletIndex = _b === void 0 ? 0 : _b, _c = _a.asset, asset = _c === void 0 ? xchainUtil.AssetRuneNative : _c, amount = _a.amount, recipient = _a.recipient, memo = _a.memo;
913
+ var _b, _c, _d, _e;
914
+ var _f = _a.walletIndex, walletIndex = _f === void 0 ? 0 : _f, _g = _a.asset, asset = _g === void 0 ? xchainUtil.AssetRuneNative : _g, amount = _a.amount, recipient = _a.recipient, memo = _a.memo;
866
915
  return __awaiter(this, void 0, void 0, function () {
867
- var assetBalance, fee, transferResult;
868
- return __generator(this, function (_d) {
869
- switch (_d.label) {
916
+ var balances, runeBalance, assetBalance, fee, transferResult;
917
+ return __generator(this, function (_h) {
918
+ switch (_h.label) {
870
919
  case 0:
871
920
  registerCodecs(getPrefix(this.network));
872
- return [4 /*yield*/, this.getBalance(this.getAddress(walletIndex), [asset])];
921
+ return [4 /*yield*/, this.getBalance(this.getAddress(walletIndex))];
873
922
  case 1:
874
- assetBalance = _d.sent();
923
+ balances = _h.sent();
924
+ runeBalance = (_c = (_b = balances.filter(function (_a) {
925
+ var asset = _a.asset;
926
+ return isAssetRuneNative(asset);
927
+ })[0]) === null || _b === void 0 ? void 0 : _b.amount) !== null && _c !== void 0 ? _c : xchainUtil.baseAmount(0, DECIMAL);
928
+ assetBalance = (_e = (_d = balances.filter(function (_a) {
929
+ var assetInList = _a.asset;
930
+ return xchainUtil.assetToString(assetInList) === xchainUtil.assetToString(asset);
931
+ })[0]) === null || _d === void 0 ? void 0 : _d.amount) !== null && _e !== void 0 ? _e : xchainUtil.baseAmount(0, DECIMAL);
875
932
  return [4 /*yield*/, this.getFees()];
876
933
  case 2:
877
- fee = _d.sent();
878
- if (assetBalance.length === 0 ||
879
- assetBalance[0].amount.amount().lt(amount.amount().plus(fee[xchainClient.FeeOption.Average].amount()))) {
880
- throw new Error('insufficient funds');
934
+ fee = (_h.sent()).average;
935
+ if (isAssetRuneNative(asset)) {
936
+ // amount + fee < runeBalance
937
+ if (runeBalance.lt(amount.plus(fee))) {
938
+ throw new Error('insufficient funds');
939
+ }
940
+ }
941
+ else {
942
+ // amount < assetBalances && runeBalance < fee
943
+ if (assetBalance.lt(amount) || runeBalance.lt(fee)) {
944
+ throw new Error('insufficient funds');
945
+ }
881
946
  }
882
947
  return [4 /*yield*/, this.cosmosClient.transfer({
883
948
  privkey: this.getPrivKey(walletIndex),
@@ -892,7 +957,7 @@ var Client = /** @class */ (function () {
892
957
  },
893
958
  })];
894
959
  case 3:
895
- transferResult = _d.sent();
960
+ transferResult = _h.sent();
896
961
  if (!isBroadcastSuccess(transferResult)) {
897
962
  throw new Error("failed to broadcast transaction: " + transferResult.txhash);
898
963
  }
@@ -908,7 +973,7 @@ var Client = /** @class */ (function () {
908
973
  * @returns {StdTx} The signed transaction.
909
974
  */
910
975
  Client.prototype.transferOffline = function (_a) {
911
- var _b = _a.walletIndex, walletIndex = _b === void 0 ? 0 : _b, _c = _a.asset, asset = _c === void 0 ? xchainUtil.AssetRuneNative : _c, amount = _a.amount, recipient = _a.recipient, memo = _a.memo, _d = _a.from_balance, from_balance = _d === void 0 ? xchainUtil.baseAmount('0', DECIMAL) : _d, _e = _a.from_account_number, from_account_number = _e === void 0 ? '0' : _e, _f = _a.from_sequence, from_sequence = _f === void 0 ? '0' : _f;
976
+ var _b = _a.walletIndex, walletIndex = _b === void 0 ? 0 : _b, _c = _a.asset, asset = _c === void 0 ? xchainUtil.AssetRuneNative : _c, amount = _a.amount, recipient = _a.recipient, memo = _a.memo, from_rune_balance = _a.from_rune_balance, _d = _a.from_asset_balance, from_asset_balance = _d === void 0 ? xchainUtil.baseAmount(0, DECIMAL) : _d, _e = _a.from_account_number, from_account_number = _e === void 0 ? '0' : _e, _f = _a.from_sequence, from_sequence = _f === void 0 ? '0' : _f;
912
977
  return __awaiter(this, void 0, void 0, function () {
913
978
  var fee, result;
914
979
  return __generator(this, function (_g) {
@@ -917,10 +982,18 @@ var Client = /** @class */ (function () {
917
982
  registerCodecs(getPrefix(this.network));
918
983
  return [4 /*yield*/, this.getFees()];
919
984
  case 1:
920
- fee = _g.sent();
921
- if (from_balance === xchainUtil.baseAmount('0', DECIMAL) ||
922
- from_balance.amount().lt(amount.amount().plus(fee[xchainClient.FeeOption.Average].amount()))) {
923
- throw new Error('insufficient funds');
985
+ fee = (_g.sent()).average;
986
+ if (isAssetRuneNative(asset)) {
987
+ // amount + fee < runeBalance
988
+ if (from_rune_balance.lt(amount.plus(fee))) {
989
+ throw new Error('insufficient funds');
990
+ }
991
+ }
992
+ else {
993
+ // amount < assetBalances && runeBalance < fee
994
+ if (from_asset_balance.lt(amount) || from_rune_balance.lt(fee)) {
995
+ throw new Error('insufficient funds');
996
+ }
924
997
  }
925
998
  return [4 /*yield*/, this.cosmosClient.transferSignedOffline({
926
999
  privkey: this.getPrivKey(walletIndex),
@@ -964,22 +1037,23 @@ exports.DEFAULT_GAS_VALUE = DEFAULT_GAS_VALUE;
964
1037
  exports.DEPOSIT_GAS_VALUE = DEPOSIT_GAS_VALUE;
965
1038
  exports.MAX_TX_COUNT = MAX_TX_COUNT;
966
1039
  exports.MsgNativeTx = MsgNativeTx;
1040
+ exports.assetFromDenom = assetFromDenom;
967
1041
  exports.buildDepositTx = buildDepositTx;
968
- exports.getAsset = getAsset;
969
1042
  exports.getBalance = getBalance;
970
1043
  exports.getChainId = getChainId;
971
1044
  exports.getDefaultClientUrl = getDefaultClientUrl;
972
1045
  exports.getDefaultExplorerUrls = getDefaultExplorerUrls;
973
1046
  exports.getDefaultFees = getDefaultFees;
974
1047
  exports.getDenom = getDenom;
975
- exports.getDenomWithChain = getDenomWithChain;
976
1048
  exports.getDepositTxDataFromLogs = getDepositTxDataFromLogs;
977
1049
  exports.getExplorerAddressUrl = getExplorerAddressUrl;
978
1050
  exports.getExplorerTxUrl = getExplorerTxUrl;
979
1051
  exports.getExplorerUrl = getExplorerUrl;
980
1052
  exports.getPrefix = getPrefix;
981
1053
  exports.getTxType = getTxType;
1054
+ exports.isAssetRuneNative = isAssetRuneNative;
982
1055
  exports.isBroadcastSuccess = isBroadcastSuccess;
1056
+ exports.isChainId = isChainId;
983
1057
  exports.isMsgMultiSend = isMsgMultiSend;
984
1058
  exports.isMsgSend = isMsgSend;
985
1059
  exports.msgNativeTxFromJson = msgNativeTxFromJson;
@@ -1,4 +1,4 @@
1
- import { Network, Tx } from '@xchainjs/xchain-client';
1
+ import { Network, Tx, TxParams } from '@xchainjs/xchain-client';
2
2
  import { Asset, BaseAmount } from '@xchainjs/xchain-util';
3
3
  export declare type NodeUrl = {
4
4
  node: string;
@@ -22,3 +22,16 @@ export declare type DepositParam = {
22
22
  memo: string;
23
23
  };
24
24
  export declare type TxData = Pick<Tx, 'from' | 'to' | 'type'>;
25
+ export declare type TxOfflineParams = TxParams & {
26
+ /**
27
+ * Balance of Rune to send from
28
+ */
29
+ from_rune_balance: BaseAmount;
30
+ /**
31
+ * Balance of asset to send from
32
+ * Optional: It can be ignored if asset to send from is RUNE
33
+ */
34
+ from_asset_balance?: BaseAmount;
35
+ from_account_number: string;
36
+ from_sequence: string;
37
+ };
package/lib/util.d.ts CHANGED
@@ -11,26 +11,26 @@ export declare const DEFAULT_GAS_VALUE = "2000000";
11
11
  export declare const DEPOSIT_GAS_VALUE = "500000000";
12
12
  export declare const MAX_TX_COUNT = 100;
13
13
  /**
14
- * Get denomination from Asset
14
+ * Checks whether an asset is `AssetRuneNative`
15
15
  *
16
16
  * @param {Asset} asset
17
- * @returns {string} The denomination of the given asset.
17
+ * @returns {boolean} `true` or `false`
18
18
  */
19
- export declare const getDenom: (asset: Asset) => string;
19
+ export declare const isAssetRuneNative: (asset: Asset) => boolean;
20
20
  /**
21
- * Get denomination with chainname from Asset
21
+ * Get denomination from Asset
22
22
  *
23
23
  * @param {Asset} asset
24
- * @returns {string} The denomination with chainname of the given asset.
24
+ * @returns {string} The denomination of the given asset.
25
25
  */
26
- export declare const getDenomWithChain: (asset: Asset) => string;
26
+ export declare const getDenom: (asset: Asset) => string;
27
27
  /**
28
28
  * Get Asset from denomination
29
29
  *
30
30
  * @param {string} denom
31
31
  * @returns {Asset|null} The asset of the given denomination.
32
32
  */
33
- export declare const getAsset: (denom: string) => Asset | null;
33
+ export declare const assetFromDenom: (denom: string) => Asset | null;
34
34
  /**
35
35
  * Type guard for MsgSend
36
36
  *
@@ -60,12 +60,26 @@ export declare const isBroadcastSuccess: (response: unknown) => boolean;
60
60
  *
61
61
  **/
62
62
  export declare const getPrefix: (network: Network) => "thor" | "sthor" | "tthor";
63
+ export declare enum ChainId {
64
+ Mainnet = "thorchain",
65
+ Stagenet = "thorchain-stagenet",
66
+ Testnet = "thorchain-v1"
67
+ }
68
+ /**
69
+ * Type guard to check whether string is a valid `ChainId`
70
+ *
71
+ * @param {string} id Chain id.
72
+ * @returns {boolean} `true` or `false`
73
+ */
74
+ export declare const isChainId: (id: string) => id is ChainId;
63
75
  /**
64
76
  * Get the chain id.
65
77
  *
78
+ * @param {Network} network
66
79
  * @returns {string} The chain id based on the network.
80
+ *
67
81
  */
68
- export declare const getChainId: () => string;
82
+ export declare const getChainId: (network: Network) => ChainId;
69
83
  /**
70
84
  * Register Codecs based on the prefix.
71
85
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xchainjs/xchain-thorchain",
3
- "version": "0.20.0",
3
+ "version": "0.21.2",
4
4
  "description": "Custom Thorchain client and utilities used by XChainJS clients",
5
5
  "keywords": [
6
6
  "THORChain",
@@ -33,11 +33,11 @@
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/big.js": "^6.0.0",
36
- "@xchainjs/xchain-client": "^0.11.0",
37
- "@xchainjs/xchain-cosmos": "^0.15.0",
36
+ "@xchainjs/xchain-client": "^0.11.1",
37
+ "@xchainjs/xchain-cosmos": "^0.16.1",
38
38
  "@xchainjs/xchain-crypto": "^0.2.4",
39
- "@xchainjs/xchain-util": "^0.3.0",
40
- "axios": "^0.21.0",
39
+ "@xchainjs/xchain-util": "^0.5.1",
40
+ "axios": "^0.25.0",
41
41
  "cosmos-client": "0.39.2",
42
42
  "nock": "^13.0.5"
43
43
  },
@@ -45,11 +45,11 @@
45
45
  "access": "public"
46
46
  },
47
47
  "peerDependencies": {
48
- "@xchainjs/xchain-client": "^0.11.0",
49
- "@xchainjs/xchain-cosmos": "^0.15.0",
48
+ "@xchainjs/xchain-client": "^0.11.1",
49
+ "@xchainjs/xchain-cosmos": "^0.16.1",
50
50
  "@xchainjs/xchain-crypto": "^0.2.4",
51
- "@xchainjs/xchain-util": "^0.3.0",
52
- "axios": "^0.21.0",
51
+ "@xchainjs/xchain-util": "^0.5.1",
52
+ "axios": "^0.25.0",
53
53
  "cosmos-client": "0.39.2"
54
54
  }
55
55
  }