@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.
- package/background/KoniTypes.d.ts +5 -1
- package/cjs/constants/index.js +7 -1
- package/cjs/koni/api/nft/config.js +11 -1
- package/cjs/koni/api/nft/index.js +9 -0
- package/cjs/koni/api/nft/ternoa_nft/index.js +174 -0
- package/cjs/koni/api/staking/bonding/utils.js +1 -1
- package/cjs/koni/background/handlers/Extension.js +67 -32
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +16 -6
- package/cjs/services/chain-service/constants.js +2 -1
- package/cjs/services/chain-service/index.js +11 -14
- package/cjs/services/earning-service/constants/chains.js +2 -1
- package/cjs/services/earning-service/handlers/native-staking/index.js +8 -1
- package/cjs/services/earning-service/handlers/native-staking/tao.js +415 -0
- package/cjs/services/earning-service/service.js +3 -0
- package/cjs/services/earning-service/utils/index.js +13 -0
- package/cjs/services/keyring-service/context/handlers/Modify.js +11 -3
- package/cjs/services/keyring-service/context/state.js +2 -3
- package/cjs/services/keyring-service/index.js +1 -1
- package/cjs/services/swap-service/handler/chainflip-handler.js +13 -5
- package/cjs/services/transaction-service/utils.js +3 -0
- package/cjs/types/swap/index.js +4 -2
- package/cjs/utils/account/derive/info/solo.js +2 -0
- package/cjs/utils/account/derive/info/unified.js +2 -0
- package/cjs/utils/account/transform.js +4 -4
- package/constants/index.d.ts +2 -0
- package/constants/index.js +2 -0
- package/koni/api/nft/config.d.ts +4 -0
- package/koni/api/nft/config.js +6 -0
- package/koni/api/nft/index.js +9 -0
- package/koni/api/nft/ternoa_nft/index.d.ts +32 -0
- package/koni/api/nft/ternoa_nft/index.js +167 -0
- package/koni/api/staking/bonding/utils.js +1 -1
- package/koni/background/handlers/Extension.d.ts +1 -0
- package/koni/background/handlers/Extension.js +38 -3
- package/package.json +16 -6
- package/packageInfo.js +1 -1
- package/services/balance-service/helpers/subscribe/substrate/index.js +10 -0
- package/services/chain-service/constants.d.ts +1 -0
- package/services/chain-service/constants.js +2 -1
- package/services/chain-service/index.js +11 -14
- package/services/earning-service/constants/chains.d.ts +1 -0
- package/services/earning-service/constants/chains.js +2 -1
- package/services/earning-service/handlers/native-staking/index.d.ts +1 -0
- package/services/earning-service/handlers/native-staking/index.js +2 -1
- package/services/earning-service/handlers/native-staking/tao.d.ts +49 -0
- package/services/earning-service/handlers/native-staking/tao.js +399 -0
- package/services/earning-service/service.js +4 -1
- package/services/earning-service/utils/index.d.ts +2 -0
- package/services/earning-service/utils/index.js +12 -0
- package/services/keyring-service/context/handlers/Modify.js +11 -3
- package/services/keyring-service/context/state.js +2 -3
- package/services/keyring-service/index.d.ts +1 -1
- package/services/keyring-service/index.js +1 -1
- package/services/swap-service/handler/chainflip-handler.js +13 -5
- package/services/transaction-service/utils.js +3 -0
- package/types/swap/index.d.ts +1 -0
- package/types/swap/index.js +2 -1
- package/utils/account/derive/info/solo.js +2 -0
- package/utils/account/derive/info/unified.js +2 -0
- 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) {
|
package/cjs/types/swap/index.js
CHANGED
|
@@ -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
|
-
//
|
|
428
|
-
|
|
429
|
-
|
|
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))) {
|
package/constants/index.d.ts
CHANGED
|
@@ -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";
|
package/constants/index.js
CHANGED
|
@@ -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';
|
package/koni/api/nft/config.d.ts
CHANGED
|
@@ -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/";
|
package/koni/api/nft/config.js
CHANGED
|
@@ -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
|
package/koni/api/nft/index.js
CHANGED
|
@@ -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
|
|
1445
|
+
return {
|
|
1446
|
+
success: true,
|
|
1447
|
+
error: ''
|
|
1448
|
+
};
|
|
1417
1449
|
} catch (e) {
|
|
1418
1450
|
console.error(e);
|
|
1419
|
-
return
|
|
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.
|
|
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.
|
|
2375
|
-
"@subwallet/extension-base": "^1.3.
|
|
2376
|
-
"@subwallet/extension-chains": "^1.3.
|
|
2377
|
-
"@subwallet/extension-dapp": "^1.3.
|
|
2378
|
-
"@subwallet/extension-inject": "^1.3.
|
|
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.
|
|
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
|
-
|
|
1577
|
-
|
|
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
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
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) {
|
|
@@ -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';
|