@subwallet/extension-base 1.3.1 → 1.3.2-0

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.
Files changed (61) hide show
  1. package/background/KoniTypes.d.ts +5 -1
  2. package/cjs/constants/index.js +7 -1
  3. package/cjs/koni/api/nft/config.js +11 -1
  4. package/cjs/koni/api/nft/index.js +9 -0
  5. package/cjs/koni/api/nft/ternoa_nft/index.js +174 -0
  6. package/cjs/koni/api/staking/bonding/utils.js +1 -1
  7. package/cjs/koni/background/handlers/Extension.js +67 -32
  8. package/cjs/packageInfo.js +1 -1
  9. package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +16 -6
  10. package/cjs/services/chain-service/constants.js +2 -1
  11. package/cjs/services/chain-service/index.js +11 -14
  12. package/cjs/services/earning-service/constants/chains.js +2 -1
  13. package/cjs/services/earning-service/handlers/native-staking/index.js +8 -1
  14. package/cjs/services/earning-service/handlers/native-staking/tao.js +415 -0
  15. package/cjs/services/earning-service/service.js +3 -0
  16. package/cjs/services/earning-service/utils/index.js +13 -0
  17. package/cjs/services/keyring-service/context/handlers/Modify.js +11 -3
  18. package/cjs/services/keyring-service/context/state.js +2 -3
  19. package/cjs/services/keyring-service/index.js +1 -1
  20. package/cjs/services/swap-service/handler/chainflip-handler.js +13 -5
  21. package/cjs/services/transaction-service/utils.js +3 -0
  22. package/cjs/types/swap/index.js +4 -2
  23. package/cjs/utils/account/derive/info/solo.js +2 -0
  24. package/cjs/utils/account/derive/info/unified.js +2 -0
  25. package/cjs/utils/account/transform.js +4 -4
  26. package/constants/index.d.ts +2 -0
  27. package/constants/index.js +2 -0
  28. package/koni/api/nft/config.d.ts +4 -0
  29. package/koni/api/nft/config.js +6 -0
  30. package/koni/api/nft/index.js +9 -0
  31. package/koni/api/nft/ternoa_nft/index.d.ts +32 -0
  32. package/koni/api/nft/ternoa_nft/index.js +167 -0
  33. package/koni/api/staking/bonding/utils.js +1 -1
  34. package/koni/background/handlers/Extension.d.ts +1 -0
  35. package/koni/background/handlers/Extension.js +38 -3
  36. package/package.json +16 -6
  37. package/packageInfo.js +1 -1
  38. package/services/balance-service/helpers/subscribe/substrate/index.js +10 -0
  39. package/services/chain-service/constants.d.ts +1 -0
  40. package/services/chain-service/constants.js +2 -1
  41. package/services/chain-service/index.js +11 -14
  42. package/services/earning-service/constants/chains.d.ts +1 -0
  43. package/services/earning-service/constants/chains.js +2 -1
  44. package/services/earning-service/handlers/native-staking/index.d.ts +1 -0
  45. package/services/earning-service/handlers/native-staking/index.js +2 -1
  46. package/services/earning-service/handlers/native-staking/tao.d.ts +49 -0
  47. package/services/earning-service/handlers/native-staking/tao.js +399 -0
  48. package/services/earning-service/service.js +4 -1
  49. package/services/earning-service/utils/index.d.ts +2 -0
  50. package/services/earning-service/utils/index.js +12 -0
  51. package/services/keyring-service/context/handlers/Modify.js +11 -3
  52. package/services/keyring-service/context/state.js +2 -3
  53. package/services/keyring-service/index.d.ts +1 -1
  54. package/services/keyring-service/index.js +1 -1
  55. package/services/swap-service/handler/chainflip-handler.js +13 -5
  56. package/services/transaction-service/utils.js +3 -0
  57. package/types/swap/index.d.ts +1 -0
  58. package/types/swap/index.js +2 -1
  59. package/utils/account/derive/info/solo.js +2 -0
  60. package/utils/account/derive/info/unified.js +2 -0
  61. package/utils/account/transform.js +4 -4
@@ -238,7 +238,6 @@ class ChainflipSwapHandler {
238
238
  switch (fee.type) {
239
239
  case ChainflipFeeType.INGRESS:
240
240
  {
241
- console.log('ingress', fee);
242
241
  feeComponent.push({
243
242
  tokenSlug: fromAsset.slug,
244
243
  amount: fee.amount,
@@ -250,7 +249,6 @@ class ChainflipSwapHandler {
250
249
  // eslint-disable-next-line no-fallthrough
251
250
  case ChainflipFeeType.EGRESS:
252
251
  {
253
- console.log('egress', fee);
254
252
  feeComponent.push({
255
253
  tokenSlug: toAsset.slug,
256
254
  amount: fee.amount,
@@ -266,7 +264,6 @@ class ChainflipSwapHandler {
266
264
  // eslint-disable-next-line no-fallthrough
267
265
  case ChainflipFeeType.BROKER:
268
266
  {
269
- console.log('broker fee', fee);
270
267
  feeComponent.push({
271
268
  tokenSlug: this.intermediaryAssetSlug,
272
269
  amount: fee.amount,
@@ -343,7 +340,8 @@ class ChainflipSwapHandler {
343
340
  const {
344
341
  address,
345
342
  quote,
346
- recipient
343
+ recipient,
344
+ slippage
347
345
  } = params;
348
346
  const pair = quote.pair;
349
347
  const fromAsset = this.chainService.getAssetBySlug(pair.from);
@@ -355,14 +353,24 @@ class ChainflipSwapHandler {
355
353
  const destChainId = this.chainMapping[toAsset.originChain];
356
354
  const fromAssetId = (0, _utils._getAssetSymbol)(fromAsset);
357
355
  const toAssetId = (0, _utils._getAssetSymbol)(toAsset);
356
+ const minReceive = new _bignumber.default(quote.rate).times(1 - slippage).toString();
358
357
  const depositAddressResponse = await this.swapSdk.requestDepositAddress({
359
358
  srcChain: srcChainId,
360
359
  destChain: destChainId,
361
360
  srcAsset: fromAssetId,
362
361
  destAsset: toAssetId,
363
362
  destAddress: receiver,
364
- amount: quote.fromAmount
363
+ amount: quote.fromAmount,
364
+ fillOrKillParams: {
365
+ minPrice: minReceive,
366
+ // minimum accepted price for swaps through the channel
367
+ refundAddress: address,
368
+ // address to which assets are refunded
369
+ retryDurationBlocks: 100 // 100 blocks * 6 seconds = 10 minutes before deposits are refunded
370
+ }
365
371
  });
372
+
373
+ console.log('depositAddressResp', depositAddressResponse);
366
374
  const txData = {
367
375
  address,
368
376
  provider: this.providerInfo,
@@ -36,6 +36,9 @@ function getBlockExplorerAccountRoute(explorerLink) {
36
36
  if (explorerLink.includes('invarch.statescan.io')) {
37
37
  return '#/accounts';
38
38
  }
39
+ if (explorerLink.includes('explorer.zkverify.io')) {
40
+ return 'account';
41
+ }
39
42
  return 'address';
40
43
  }
41
44
  function getBlockExplorerTxRoute(chainInfo) {
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports._SUPPORTED_SWAP_PROVIDERS = exports.SwapStepType = exports.SwapProviderId = exports.SwapFeeType = exports.SwapErrorType = void 0;
6
+ exports._SUPPORTED_SWAP_PROVIDERS = exports.SwapStepType = exports.SwapProviderId = exports.SwapFeeType = exports.SwapErrorType = exports.CHAINFLIP_SLIPPAGE = void 0;
7
7
  // Copyright 2019-2022 @subwallet/extension-base
8
8
  // SPDX-License-Identifier: Apache-2.0
9
9
  // core
@@ -47,4 +47,6 @@ exports.SwapFeeType = SwapFeeType;
47
47
  SwapFeeType["PLATFORM_FEE"] = "PLATFORM_FEE";
48
48
  SwapFeeType["NETWORK_FEE"] = "NETWORK_FEE";
49
49
  SwapFeeType["WALLET_FEE"] = "WALLET_FEE";
50
- })(SwapFeeType || (exports.SwapFeeType = SwapFeeType = {}));
50
+ })(SwapFeeType || (exports.SwapFeeType = SwapFeeType = {}));
51
+ const CHAINFLIP_SLIPPAGE = 0.02; // Example: 0.01 for 1%
52
+ exports.CHAINFLIP_SLIPPAGE = CHAINFLIP_SLIPPAGE;
@@ -198,6 +198,8 @@ const findSoloNextDerive = parentAddress => {
198
198
  }
199
199
  if (deriveIndex === index) {
200
200
  index++;
201
+ } else if (currentDepth === 0 && deriveIndex === 0 && index > deriveIndex) {
202
+ // Special case for the first account on the root
201
203
  } else {
202
204
  break;
203
205
  }
@@ -95,6 +95,8 @@ const findUnifiedNextDerive = (proxyId, accounts) => {
95
95
  }
96
96
  if (deriveIndex === index) {
97
97
  index++;
98
+ } else if (currentDepth === 0 && deriveIndex === 0 && index > deriveIndex) {
99
+ // Special case for the first account on the root
98
100
  } else {
99
101
  break;
100
102
  }
@@ -424,10 +424,10 @@ const _combineAccounts = (accounts, modifyPairs, accountProxies) => {
424
424
  accountActions.push(_types2.AccountActions.EXPORT_MNEMONIC);
425
425
  }
426
426
 
427
- // // Json
428
- // if (value.accounts.every((account) => account.accountActions.includes(AccountActions.EXPORT_JSON))) {
429
- // accountActions.push(AccountActions.EXPORT_JSON);
430
- // }
427
+ // Json
428
+ if (value.accounts.every(account => account.accountActions.includes(_types2.AccountActions.EXPORT_JSON))) {
429
+ accountActions.push(_types2.AccountActions.EXPORT_JSON);
430
+ }
431
431
 
432
432
  // Derive
433
433
  if (value.accounts.every(account => account.accountActions.includes(_types2.AccountActions.DERIVE))) {
@@ -18,6 +18,8 @@ export declare const CRON_REFRESH_CHAIN_NOMINATOR_METADATA = 1800000;
18
18
  export declare const CRON_RECOVER_HISTORY_INTERVAL = 30000;
19
19
  export declare const CRON_SYNC_MANTA_PAY = 300000;
20
20
  export declare const MANTA_PAY_BALANCE_INTERVAL = 30000;
21
+ export declare const BITTENSOR_REFRESH_STAKE_INFO = 30000;
22
+ export declare const BITTENSOR_REFRESH_STAKE_APY = 300000;
21
23
  export declare const CRON_REFRESH_EARNING_REWARD_HISTORY_INTERVAL: number;
22
24
  export declare const ALL_ACCOUNT_KEY = "ALL";
23
25
  export declare const ALL_NETWORK_KEY = "all";
@@ -20,6 +20,8 @@ export const CRON_REFRESH_CHAIN_NOMINATOR_METADATA = 1800000;
20
20
  export const CRON_RECOVER_HISTORY_INTERVAL = 30000;
21
21
  export const CRON_SYNC_MANTA_PAY = 300000;
22
22
  export const MANTA_PAY_BALANCE_INTERVAL = 30000;
23
+ export const BITTENSOR_REFRESH_STAKE_INFO = 30000;
24
+ export const BITTENSOR_REFRESH_STAKE_APY = 300000;
23
25
  export const CRON_REFRESH_EARNING_REWARD_HISTORY_INTERVAL = 15 * BASE_MINUTE_INTERVAL;
24
26
  export const ALL_ACCOUNT_KEY = 'ALL';
25
27
  export const ALL_NETWORK_KEY = 'all';
@@ -23,6 +23,10 @@ export declare const IPFS_W3S_LINK = "https://w3s.link/ipfs/";
23
23
  export declare const GATEWAY_IPFS_IO = "https://gateway.ipfs.io/ipfs/";
24
24
  export declare const IPFS_IO = "https://ipfs.io/ipfs/";
25
25
  export declare const DWEB_LINK = "https://dweb.link/ipfs/";
26
+ export declare const TERNOA_MAINNET_CLIENT_NFT = "https://indexer-mainnet.ternoa.dev";
27
+ export declare const TERNOA_ALPHANET_CLIENT_NFT = "https://indexer-alphanet.ternoa.dev";
28
+ export declare const TERNOA_MAINNET_GATEWAY = "https://ipfs-mainnet.trnnfr.com/ipfs/";
29
+ export declare const TERNOA_ALPHANET_GATEWAY = "https://ipfs-dev.trnnfr.com/ipfs/";
26
30
  export declare const IPFS_GATEWAY_4EVERLAND = "https://4everland.io/ipfs/";
27
31
  export declare const IPFS_FLEEK = "https://ipfs.fleek.co/ipfs/";
28
32
  export declare const W3S_IPFS = "https://w3s.link/ipfs/";
@@ -48,6 +48,12 @@ export const IPFS_IO = 'https://ipfs.io/ipfs/';
48
48
 
49
49
  // XOrigin
50
50
  export const DWEB_LINK = 'https://dweb.link/ipfs/';
51
+
52
+ // XOrigin
53
+ export const TERNOA_MAINNET_CLIENT_NFT = 'https://indexer-mainnet.ternoa.dev';
54
+ export const TERNOA_ALPHANET_CLIENT_NFT = 'https://indexer-alphanet.ternoa.dev';
55
+ export const TERNOA_MAINNET_GATEWAY = 'https://ipfs-mainnet.trnnfr.com/ipfs/';
56
+ export const TERNOA_ALPHANET_GATEWAY = 'https://ipfs-dev.trnnfr.com/ipfs/';
51
57
  export const IPFS_GATEWAY_4EVERLAND = 'https://4everland.io/ipfs/';
52
58
  export const IPFS_FLEEK = 'https://ipfs.fleek.co/ipfs/';
53
59
  export const W3S_IPFS = 'https://w3s.link/ipfs/'; // 400
@@ -17,6 +17,7 @@ import { _NFT_CHAIN_GROUP } from '@subwallet/extension-base/services/chain-servi
17
17
  import { _isChainSupportEvmNft, _isChainSupportNativeNft, _isChainSupportWasmNft, _isSupportOrdinal } from '@subwallet/extension-base/services/chain-service/utils';
18
18
  import { categoryAddresses, targetIsWeb } from '@subwallet/extension-base/utils';
19
19
  import AssetHubNftsPalletApi from "./assethub_nft/index.js";
20
+ import { TernoaNftApi } from "./ternoa_nft/index.js";
20
21
  function createSubstrateNftApi(chain, substrateApi, addresses) {
21
22
  const {
22
23
  evm: evmAddresses,
@@ -42,6 +43,8 @@ function createSubstrateNftApi(chain, substrateApi, addresses) {
42
43
  return [new VaraNftApi(chain, substrateAddresses)];
43
44
  } else if (_NFT_CHAIN_GROUP.avail.includes(chain)) {
44
45
  return [new BlobInscriptionApi(chain, substrateAddresses)];
46
+ } else if (_NFT_CHAIN_GROUP.ternoa.includes(chain)) {
47
+ return [new TernoaNftApi(substrateApi, substrateAddresses, chain)];
45
48
  }
46
49
  return null;
47
50
  }
@@ -139,6 +142,12 @@ export class NftHandler {
139
142
  this.handlers.push(...handlers);
140
143
  }
141
144
  }
145
+ if (chain === 'ternoa') {
146
+ const handlers = createSubstrateNftApi(chain, this.substrateApiMap[chain], substrateAddresses);
147
+ if (handlers && !!handlers.length) {
148
+ this.handlers.push(...handlers);
149
+ }
150
+ }
142
151
  if (_isChainSupportWasmNft(chainInfo)) {
143
152
  if (this.substrateApiMap[chain]) {
144
153
  const handler = createWasmNftApi(chain, this.substrateApiMap[chain], substrateAddresses);
@@ -0,0 +1,32 @@
1
+ import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
2
+ import { BaseNftApi, HandleNftParams } from '../nft';
3
+ interface NftMetadata {
4
+ nftId: string;
5
+ owner: string;
6
+ creator: string;
7
+ collectionId: string;
8
+ offchainData: string;
9
+ }
10
+ interface NftDetail {
11
+ title: string;
12
+ description: string;
13
+ image: string;
14
+ }
15
+ interface CollectionDetail {
16
+ name: string;
17
+ banner_image: string;
18
+ }
19
+ export declare class TernoaNftApi extends BaseNftApi {
20
+ constructor(api: _SubstrateApi | null, addresses: string[], chain: string);
21
+ endpoint: string;
22
+ parseUrl(input: string): string | undefined;
23
+ private static parseNftRequest;
24
+ fetchNftsWithDetail(address: string): Promise<Array<{
25
+ metadata: NftMetadata;
26
+ detail: NftDetail;
27
+ }> | null>;
28
+ getCollectionDetail(collectionId: string): Promise<CollectionDetail | null>;
29
+ handleNfts(params: HandleNftParams): Promise<void>;
30
+ fetchNfts(params: HandleNftParams): Promise<number>;
31
+ }
32
+ export {};
@@ -0,0 +1,167 @@
1
+ // Copyright 2019-2022 @subwallet/extension-koni authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { baseParseIPFSUrl } from '@subwallet/extension-base/utils';
5
+ import { decodeAddress, encodeAddress } from '@polkadot/util-crypto';
6
+ import { TERNOA_MAINNET_CLIENT_NFT, TERNOA_MAINNET_GATEWAY } from "../config.js";
7
+ import { BaseNftApi } from "../nft.js";
8
+ export class TernoaNftApi extends BaseNftApi {
9
+ constructor(api, addresses, chain) {
10
+ super(chain, api, addresses);
11
+ }
12
+ endpoint = TERNOA_MAINNET_CLIENT_NFT;
13
+ parseUrl(input) {
14
+ return baseParseIPFSUrl(input, TERNOA_MAINNET_GATEWAY);
15
+ }
16
+ static parseNftRequest(address) {
17
+ return {
18
+ query: `
19
+ query {
20
+ nftEntities(
21
+ filter: {
22
+ owner: { equalTo: "${address}" }
23
+ }
24
+ ) {
25
+ totalCount
26
+ nodes {
27
+ nftId
28
+ owner
29
+ creator
30
+ collectionId
31
+ offchainData
32
+ }
33
+ }
34
+ }`
35
+ };
36
+ }
37
+
38
+ /* GET NFTs */
39
+
40
+ async fetchNftsWithDetail(address) {
41
+ const query = TernoaNftApi.parseNftRequest(address);
42
+ try {
43
+ const response = await fetch(this.endpoint, {
44
+ method: 'POST',
45
+ headers: {
46
+ 'Content-Type': 'application/json'
47
+ },
48
+ body: JSON.stringify(query)
49
+ });
50
+ const result = await response.json();
51
+ const nftEntities = result.data.nftEntities.nodes;
52
+ if (!nftEntities) {
53
+ return null;
54
+ }
55
+ const nftDetails = await Promise.all(nftEntities.map(async nft => {
56
+ const ipfsUrl = `${TERNOA_MAINNET_GATEWAY}${nft.offchainData}`;
57
+ try {
58
+ const ipfsResponse = await fetch(ipfsUrl);
59
+ const nftDetail = await ipfsResponse.json();
60
+ nftDetail.image = `${TERNOA_MAINNET_GATEWAY}${nftDetail.image}`;
61
+ return {
62
+ metadata: nft,
63
+ detail: nftDetail
64
+ };
65
+ } catch (err) {
66
+ console.error('Error:', err);
67
+ return null;
68
+ }
69
+ }));
70
+ return nftDetails.filter(nft => nft !== null);
71
+ } catch (err) {
72
+ console.error('Error:', err);
73
+ return null;
74
+ }
75
+ }
76
+
77
+ /* GET NFTs */
78
+
79
+ /* GET Collection */
80
+
81
+ async getCollectionDetail(collectionId) {
82
+ if (!this.substrateApi) {
83
+ return null;
84
+ }
85
+ const substrateApi = await this.substrateApi.isReady;
86
+ try {
87
+ const collectionMetadata = (await substrateApi.api.query.nft.collections(parseInt(collectionId))).toHuman();
88
+ if (!(collectionMetadata !== null && collectionMetadata !== void 0 && collectionMetadata.offchainData)) {
89
+ return null;
90
+ }
91
+ const ipfsUrl = `${TERNOA_MAINNET_GATEWAY}${collectionMetadata.offchainData}`;
92
+ const ipfsResponse = await fetch(ipfsUrl);
93
+ if (!ipfsResponse.ok) {
94
+ return {
95
+ name: collectionMetadata.offchainData,
96
+ banner_image: ''
97
+ };
98
+ }
99
+ const collectionDetail = await ipfsResponse.json();
100
+ collectionDetail.banner_image = `${TERNOA_MAINNET_GATEWAY}${collectionDetail.banner_image}`;
101
+ return collectionDetail;
102
+ } catch (err) {
103
+ console.error('Error:', err);
104
+ return null;
105
+ }
106
+ }
107
+
108
+ /* Get Collection */
109
+
110
+ async handleNfts(params) {
111
+ const collectionMap = new Map();
112
+ await Promise.all(this.addresses.map(async address => {
113
+ address = encodeAddress(decodeAddress(address), 42);
114
+ const nftDetails = await this.fetchNftsWithDetail(address);
115
+ if (!nftDetails || nftDetails.length === 0) {
116
+ return;
117
+ }
118
+
119
+ // eslint-disable-next-line @typescript-eslint/require-await
120
+ await Promise.all(nftDetails.map(async nft => {
121
+ const {
122
+ detail,
123
+ metadata
124
+ } = nft;
125
+ let collectionId = metadata.collectionId;
126
+ if (!collectionId) {
127
+ collectionId = 'Ternoa_Collection';
128
+ }
129
+ const parsedNft = {
130
+ id: metadata.nftId,
131
+ name: detail.title,
132
+ description: detail.description,
133
+ image: detail.image ? this.parseUrl(detail.image) : undefined,
134
+ collectionId,
135
+ chain: this.chain,
136
+ owner: address
137
+ };
138
+ params.updateItem(this.chain, parsedNft, address);
139
+ if (!collectionMap.has(collectionId)) {
140
+ collectionMap.set(collectionId, true);
141
+ }
142
+ }));
143
+ }));
144
+ for (const collectionId of collectionMap.keys()) {
145
+ const collectionDetail = collectionId !== 'Ternoa_Collection' ? await this.getCollectionDetail(collectionId) : {
146
+ name: 'Ternoa NFTs',
147
+ description: 'Collection for NFTs without a specific collection',
148
+ banner_image: ''
149
+ };
150
+ const parsedCollection = {
151
+ collectionId,
152
+ chain: this.chain,
153
+ collectionName: collectionDetail === null || collectionDetail === void 0 ? void 0 : collectionDetail.name,
154
+ image: collectionDetail !== null && collectionDetail !== void 0 && collectionDetail.banner_image ? this.parseUrl(collectionDetail === null || collectionDetail === void 0 ? void 0 : collectionDetail.banner_image) : undefined
155
+ };
156
+ params.updateCollection(this.chain, parsedCollection);
157
+ }
158
+ }
159
+ async fetchNfts(params) {
160
+ try {
161
+ await this.handleNfts(params);
162
+ } catch (e) {
163
+ return 0;
164
+ }
165
+ return 1;
166
+ }
167
+ }
@@ -326,7 +326,7 @@ export function getEarningStatusByNominations(bnTotalActiveStake, nominationList
326
326
  export function getValidatorLabel(chain) {
327
327
  if (_STAKING_CHAIN_GROUP.astar.includes(chain)) {
328
328
  return 'dApp';
329
- } else if (_STAKING_CHAIN_GROUP.relay.includes(chain)) {
329
+ } else if (_STAKING_CHAIN_GROUP.relay.includes(chain) || _STAKING_CHAIN_GROUP.bittensor.includes(chain)) {
330
330
  return 'Validator';
331
331
  }
332
332
  return 'Collator';
@@ -126,6 +126,7 @@ export default class KoniExtension {
126
126
  private validateNetwork;
127
127
  private resetDefaultNetwork;
128
128
  private recoverDotSamaApi;
129
+ private validateERC721Token;
129
130
  private upsertCustomToken;
130
131
  private deleteCustomAsset;
131
132
  private validateCustomAsset;
@@ -3,6 +3,7 @@
3
3
 
4
4
  import { Common } from '@ethereumjs/common';
5
5
  import { LegacyTransaction } from '@ethereumjs/tx';
6
+ import { _AssetType } from '@subwallet/chain-list/types';
6
7
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
7
8
  import { withErrorLog } from '@subwallet/extension-base/background/handlers/helpers';
8
9
  import { createSubscription } from '@subwallet/extension-base/background/handlers/subscriptions';
@@ -12,7 +13,7 @@ import { additionalValidateTransfer, additionalValidateXcmTransfer, validateTran
12
13
  import { _isSnowBridgeXcm } from '@subwallet/extension-base/core/substrate/xcm-parser';
13
14
  import { ALLOWED_PATH } from '@subwallet/extension-base/defaults';
14
15
  import { getERC20SpendingApprovalTx } from '@subwallet/extension-base/koni/api/contract-handler/evm/web3';
15
- import { isSnowBridgeGatewayContract } from '@subwallet/extension-base/koni/api/contract-handler/utils';
16
+ import { _ERC721_ABI, isSnowBridgeGatewayContract } from '@subwallet/extension-base/koni/api/contract-handler/utils';
16
17
  import { resolveAzeroAddressToDomain, resolveAzeroDomainToAddress } from '@subwallet/extension-base/koni/api/dotsama/domain';
17
18
  import { parseSubstrateTransaction } from '@subwallet/extension-base/koni/api/dotsama/parseTransaction';
18
19
  import { UNSUPPORTED_TRANSFER_EVM_CHAIN_NAME } from '@subwallet/extension-base/koni/api/nft/config';
@@ -1410,13 +1411,47 @@ export default class KoniExtension {
1410
1411
  return false;
1411
1412
  }
1412
1413
  }
1414
+ async validateERC721Token(data) {
1415
+ var _data$metadata;
1416
+ const evmApi = this.#koniState.getEvmApi(data.originChain);
1417
+
1418
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
1419
+ const tokenContract = new evmApi.api.eth.Contract(_ERC721_ABI, (_data$metadata = data.metadata) === null || _data$metadata === void 0 ? void 0 : _data$metadata.contractAddress);
1420
+ try {
1421
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
1422
+ await tokenContract.methods.tokenOfOwnerByIndex('0xB7fdD27a8Df011816205a6e3cAA097DC4D8C2C5d', 1).call();
1423
+ return true;
1424
+ } catch (err) {
1425
+ const error = err;
1426
+ if (error.message.includes('ERC721Enumerable: owner index out of bounds')) {
1427
+ return true;
1428
+ } else {
1429
+ return false;
1430
+ }
1431
+ }
1432
+ }
1413
1433
  async upsertCustomToken(data) {
1414
1434
  try {
1435
+ if (data.assetType === _AssetType.ERC721) {
1436
+ const isCompatible = await this.validateERC721Token(data);
1437
+ if (!isCompatible) {
1438
+ return {
1439
+ success: false,
1440
+ error: 'incompatibleNFT'
1441
+ };
1442
+ }
1443
+ }
1415
1444
  await this.#koniState.upsertCustomToken(data);
1416
- return true;
1445
+ return {
1446
+ success: true,
1447
+ error: ''
1448
+ };
1417
1449
  } catch (e) {
1418
1450
  console.error(e);
1419
- return false;
1451
+ return {
1452
+ success: false,
1453
+ error: 'Error'
1454
+ };
1420
1455
  }
1421
1456
  }
1422
1457
  async deleteCustomAsset(assetSlug) {
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "./cjs/detectPackage.js"
18
18
  ],
19
19
  "type": "module",
20
- "version": "1.3.1",
20
+ "version": "1.3.2-0",
21
21
  "main": "./cjs/index.js",
22
22
  "module": "./index.js",
23
23
  "types": "./index.d.ts",
@@ -388,6 +388,11 @@
388
388
  "require": "./cjs/koni/api/nft/rmrk_nft/index.js",
389
389
  "default": "./koni/api/nft/rmrk_nft/index.js"
390
390
  },
391
+ "./koni/api/nft/ternoa_nft": {
392
+ "types": "./koni/api/nft/ternoa_nft/index.d.ts",
393
+ "require": "./cjs/koni/api/nft/ternoa_nft/index.js",
394
+ "default": "./koni/api/nft/ternoa_nft/index.js"
395
+ },
391
396
  "./koni/api/nft/transfer": {
392
397
  "types": "./koni/api/nft/transfer.d.ts",
393
398
  "require": "./cjs/koni/api/nft/transfer.js",
@@ -996,6 +1001,11 @@
996
1001
  "require": "./cjs/services/earning-service/handlers/native-staking/relay-chain.js",
997
1002
  "default": "./services/earning-service/handlers/native-staking/relay-chain.js"
998
1003
  },
1004
+ "./services/earning-service/handlers/native-staking/tao": {
1005
+ "types": "./services/earning-service/handlers/native-staking/tao.d.ts",
1006
+ "require": "./cjs/services/earning-service/handlers/native-staking/tao.js",
1007
+ "default": "./services/earning-service/handlers/native-staking/tao.js"
1008
+ },
999
1009
  "./services/earning-service/handlers/nomination-pool": {
1000
1010
  "types": "./services/earning-service/handlers/nomination-pool/index.d.ts",
1001
1011
  "require": "./cjs/services/earning-service/handlers/nomination-pool/index.js",
@@ -2371,11 +2381,11 @@
2371
2381
  "@reduxjs/toolkit": "^1.9.1",
2372
2382
  "@sora-substrate/type-definitions": "^1.17.7",
2373
2383
  "@substrate/connect": "^0.8.9",
2374
- "@subwallet/chain-list": "0.2.88",
2375
- "@subwallet/extension-base": "^1.3.1",
2376
- "@subwallet/extension-chains": "^1.3.1",
2377
- "@subwallet/extension-dapp": "^1.3.1",
2378
- "@subwallet/extension-inject": "^1.3.1",
2384
+ "@subwallet/chain-list": "0.2.89",
2385
+ "@subwallet/extension-base": "^1.3.2-0",
2386
+ "@subwallet/extension-chains": "^1.3.2-0",
2387
+ "@subwallet/extension-dapp": "^1.3.2-0",
2388
+ "@subwallet/extension-inject": "^1.3.2-0",
2379
2389
  "@subwallet/keyring": "^0.1.8-beta.0",
2380
2390
  "@subwallet/ui-keyring": "^0.1.8-beta.0",
2381
2391
  "@ton/core": "^0.56.3",
package/packageInfo.js CHANGED
@@ -7,5 +7,5 @@ export const packageInfo = {
7
7
  name: '@subwallet/extension-base',
8
8
  path: (import.meta && import.meta.url) ? new URL(import.meta.url).pathname.substring(0, new URL(import.meta.url).pathname.lastIndexOf('/') + 1) : 'auto',
9
9
  type: 'esm',
10
- version: '1.3.1'
10
+ version: '1.3.2-0'
11
11
  };
@@ -15,6 +15,8 @@ import { getPSP22ContractPromise } from '@subwallet/extension-base/koni/api/cont
15
15
  import { getDefaultWeightV2 } from '@subwallet/extension-base/koni/api/contract-handler/wasm/utils';
16
16
  import { _BALANCE_CHAIN_GROUP, _MANTA_ZK_CHAIN_GROUP, _ZK_ASSET_PREFIX } from '@subwallet/extension-base/services/chain-service/constants';
17
17
  import { _checkSmartContractSupportByChain, _getAssetExistentialDeposit, _getChainExistentialDeposit, _getChainNativeTokenSlug, _getContractAddressOfToken, _getTokenOnChainAssetId, _getTokenOnChainInfo, _getTokenTypesSupportedByChain, _getXcmAssetMultilocation, _isBridgedToken, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils';
18
+ import { fetchTaoDelegateState } from '@subwallet/extension-base/services/earning-service/handlers/native-staking/tao';
19
+ import { getTaoTotalStake } from '@subwallet/extension-base/services/earning-service/utils';
18
20
  import { filterAssetsByChainAndType } from '@subwallet/extension-base/utils';
19
21
  import BigN from 'bignumber.js';
20
22
  import { subscribeERC20Interval } from "../evm.js";
@@ -129,6 +131,13 @@ const subscribeWithSystemAccountPallet = async ({
129
131
  args: addresses
130
132
  });
131
133
  }
134
+ let bittensorStakingBalances = new Array(addresses.length).fill(BigInt(0));
135
+ if (['bittensor'].includes(chainInfo.slug)) {
136
+ bittensorStakingBalances = await Promise.all(addresses.map(async address => {
137
+ const rawDelegateState = await fetchTaoDelegateState(address);
138
+ return getTaoTotalStake(rawDelegateState);
139
+ }));
140
+ }
132
141
  const subscription = substrateApi.subscribeDataWithMulti(params, rs => {
133
142
  const balances = rs[systemAccountKey];
134
143
  const poolMemberInfos = rs[poolMembersKey];
@@ -142,6 +151,7 @@ const subscribeWithSystemAccountPallet = async ({
142
151
  const nominationPoolBalance = poolMemberInfo ? _getTotalStakeInNominationPool(poolMemberInfo) : BigInt(0);
143
152
  totalLockedFromTransfer += nominationPoolBalance;
144
153
  }
154
+ totalLockedFromTransfer += bittensorStakingBalances[index];
145
155
  return {
146
156
  address: addresses[index],
147
157
  tokenSlug: _getChainNativeTokenSlug(chainInfo),
@@ -36,6 +36,7 @@ export declare const _NFT_CHAIN_GROUP: {
36
36
  bitcountry: string[];
37
37
  vara: string[];
38
38
  avail: string[];
39
+ ternoa: string[];
39
40
  };
40
41
  export declare const _STAKING_ERA_LENGTH_MAP: Record<string, number>;
41
42
  export declare const _EXPECTED_BLOCK_TIME: Record<string, number>;
@@ -51,7 +51,8 @@ export const _NFT_CHAIN_GROUP = {
51
51
  unique_evm: ['unique_evm'],
52
52
  bitcountry: ['bitcountry', 'pioneer', 'continuum_network'],
53
53
  vara: ['vara_network'],
54
- avail: ['avail_mainnet']
54
+ avail: ['avail_mainnet'],
55
+ ternoa: ['ternoa', 'ternoa_alphanet']
55
56
  };
56
57
 
57
58
  // Staking--------------------------------------------------------------------------------------------------------------
@@ -1573,21 +1573,18 @@ export class ChainService {
1573
1573
  const assetSettings = await this.getAssetSettings();
1574
1574
  const activeChainSlugs = this.getActiveChainSlugs();
1575
1575
  const assetRegistry = this.getAssetRegistry();
1576
- if (Object.keys(assetSettings).length === 0) {
1577
- // only initiate the first time
1578
- Object.values(assetRegistry).forEach(assetInfo => {
1579
- const isSettingExisted = (assetInfo.slug in assetSettings);
1576
+ Object.values(assetRegistry).forEach(assetInfo => {
1577
+ const isSettingExisted = (assetInfo.slug in assetSettings);
1580
1578
 
1581
- // Set visible for every enabled chains
1582
- if (activeChainSlugs.includes(assetInfo.originChain) && !isSettingExisted) {
1583
- // Setting only exist when set either by chain settings or user
1584
- assetSettings[assetInfo.slug] = {
1585
- visible: true
1586
- };
1587
- }
1588
- });
1589
- this.setAssetSettings(assetSettings, false);
1590
- }
1579
+ // Set visible for every enabled chains
1580
+ if (activeChainSlugs.includes(assetInfo.originChain) && !isSettingExisted) {
1581
+ // Setting only exist when set either by chain settings or user
1582
+ assetSettings[assetInfo.slug] = {
1583
+ visible: true
1584
+ };
1585
+ }
1586
+ });
1587
+ this.setAssetSettings(assetSettings, false);
1591
1588
  this.eventService.emit('asset.ready', true);
1592
1589
  }
1593
1590
  setAssetSettings(assetSettings, emitEvent = true) {
@@ -12,6 +12,7 @@ export declare const _STAKING_CHAIN_GROUP: {
12
12
  lending: string[];
13
13
  krest_network: string[];
14
14
  manta: string[];
15
+ bittensor: string[];
15
16
  };
16
17
  export declare const TON_CHAINS: string[];
17
18
  export declare const MaxEraRewardPointsEras = 14;
@@ -16,7 +16,8 @@ export const _STAKING_CHAIN_GROUP = {
16
16
  liquidStaking: ['bifrost_dot', 'acala', 'parallel', 'moonbeam'],
17
17
  lending: ['interlay'],
18
18
  krest_network: ['krest_network'],
19
- manta: ['manta_network']
19
+ manta: ['manta_network'],
20
+ bittensor: ['bittensor', 'bittensor_devnet']
20
21
  };
21
22
  export const TON_CHAINS = ['ton', 'ton_testnet'];
22
23
  export const MaxEraRewardPointsEras = 14;
@@ -2,3 +2,4 @@ export { default as AmplitudeNativeStakingPoolHandler } from './amplitude';
2
2
  export { default as AstarNativeStakingPoolHandler } from './astar';
3
3
  export { default as RelayNativeStakingPoolHandler } from './relay-chain';
4
4
  export { default as ParaNativeStakingPoolHandler } from './para-chain';
5
+ export { default as TaoNativeStakingPoolHandler } from './tao';