@subwallet/extension-base 1.3.24-0 → 1.3.25-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 +9 -1
- package/background/KoniTypes.js +1 -0
- package/background/errors/EvmProviderError.js +4 -0
- package/background/errors/ProviderError.d.ts +1 -1
- package/background/errors/ProviderError.js +2 -2
- package/cjs/background/KoniTypes.js +1 -0
- package/cjs/background/errors/EvmProviderError.js +4 -0
- package/cjs/background/errors/ProviderError.js +2 -2
- package/cjs/koni/background/handlers/Tabs.js +3 -2
- package/cjs/packageInfo.js +1 -1
- package/cjs/page/index.js +1 -1
- package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +3 -3
- package/cjs/services/buy-service/constants/token.js +3 -0
- package/cjs/services/earning-service/constants/chains.js +1 -1
- package/cjs/services/earning-service/handlers/base.js +11 -5
- package/cjs/services/earning-service/handlers/native-staking/base-para.js +7 -6
- package/cjs/services/earning-service/handlers/native-staking/base.js +6 -3
- package/cjs/services/earning-service/handlers/native-staking/dtao.js +444 -0
- package/cjs/services/earning-service/handlers/native-staking/index.js +8 -1
- package/cjs/services/earning-service/handlers/native-staking/tao.js +138 -125
- package/cjs/services/earning-service/service.js +14 -4
- package/cjs/services/inapp-notification-service/index.js +3 -0
- package/cjs/services/transaction-service/index.js +6 -0
- package/cjs/types/yield/info/base.js +1 -0
- package/cjs/utils/fetchEvmChainInfo.js +10 -5
- package/koni/background/handlers/Tabs.js +3 -2
- package/package.json +11 -6
- package/packageInfo.js +1 -1
- package/page/index.js +1 -1
- package/services/balance-service/helpers/subscribe/substrate/index.js +2 -2
- package/services/buy-service/constants/token.js +3 -0
- package/services/earning-service/constants/chains.js +1 -1
- package/services/earning-service/handlers/base.d.ts +7 -5
- package/services/earning-service/handlers/base.js +11 -7
- package/services/earning-service/handlers/native-staking/base-para.d.ts +1 -1
- package/services/earning-service/handlers/native-staking/base-para.js +7 -6
- package/services/earning-service/handlers/native-staking/base.d.ts +1 -1
- package/services/earning-service/handlers/native-staking/base.js +6 -3
- package/services/earning-service/handlers/native-staking/dtao.d.ts +64 -0
- package/services/earning-service/handlers/native-staking/dtao.js +434 -0
- 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 +16 -4
- package/services/earning-service/handlers/native-staking/tao.js +136 -121
- package/services/earning-service/service.d.ts +1 -0
- package/services/earning-service/service.js +15 -5
- package/services/inapp-notification-service/index.js +3 -0
- package/services/transaction-service/index.js +6 -0
- package/types/bridge/index.d.ts +1 -0
- package/types/buy.d.ts +1 -1
- package/types/yield/actions/join/step.d.ts +1 -0
- package/types/yield/actions/join/submit.d.ts +1 -0
- package/types/yield/info/account/info.d.ts +14 -1
- package/types/yield/info/base.d.ts +3 -1
- package/types/yield/info/base.js +1 -0
- package/types/yield/info/chain/info.d.ts +5 -1
- package/utils/fetchEvmChainInfo.d.ts +1 -1
- package/utils/fetchEvmChainInfo.js +10 -5
|
@@ -107,12 +107,12 @@ export default class BasePoolHandler {
|
|
|
107
107
|
get isPoolSupportAlternativeFee() {
|
|
108
108
|
return false;
|
|
109
109
|
}
|
|
110
|
-
async getPoolInfo() {
|
|
111
|
-
return await this.state.earningService.getYieldPool(
|
|
110
|
+
async getPoolInfo(slug = this.slug) {
|
|
111
|
+
return await this.state.earningService.getYieldPool(slug);
|
|
112
112
|
}
|
|
113
|
-
async getPoolPosition(address) {
|
|
113
|
+
async getPoolPosition(address, slug = this.slug) {
|
|
114
114
|
const originAddress = reformatAddress(address);
|
|
115
|
-
return await this.state.earningService.getYieldPosition(originAddress,
|
|
115
|
+
return await this.state.earningService.getYieldPosition(originAddress, slug);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
/* Subscribe data */
|
|
@@ -127,7 +127,7 @@ export default class BasePoolHandler {
|
|
|
127
127
|
|
|
128
128
|
async earlyValidate(request) {
|
|
129
129
|
var _poolInfo$statistic, _poolInfo$statistic2, _poolInfo$statistic2$;
|
|
130
|
-
const poolInfo = await this.getPoolInfo();
|
|
130
|
+
const poolInfo = await this.getPoolInfo(request.slug);
|
|
131
131
|
if (!poolInfo || !((_poolInfo$statistic = poolInfo.statistic) !== null && _poolInfo$statistic !== void 0 && _poolInfo$statistic.earningThreshold.join)) {
|
|
132
132
|
return {
|
|
133
133
|
passed: false,
|
|
@@ -249,11 +249,11 @@ export default class BasePoolHandler {
|
|
|
249
249
|
/** Validate param to join the pool */
|
|
250
250
|
|
|
251
251
|
/** Create `transaction` to leave the pool */
|
|
252
|
-
async handleYieldLeave(fastLeave, amount, address, selectedTarget) {
|
|
252
|
+
async handleYieldLeave(fastLeave, amount, address, selectedTarget, netuid) {
|
|
253
253
|
if (fastLeave) {
|
|
254
254
|
return this.handleYieldRedeem(amount, address, selectedTarget);
|
|
255
255
|
} else {
|
|
256
|
-
return this.handleYieldUnstake(amount, address, selectedTarget);
|
|
256
|
+
return this.handleYieldUnstake(amount, address, selectedTarget, netuid);
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
259
|
|
|
@@ -263,5 +263,9 @@ export default class BasePoolHandler {
|
|
|
263
263
|
|
|
264
264
|
/** Create `transaction` to withdraw unstaked amount */
|
|
265
265
|
|
|
266
|
+
/** Check handler can handle slug */
|
|
267
|
+
canHandleSlug(slug) {
|
|
268
|
+
return this.slug === slug;
|
|
269
|
+
}
|
|
266
270
|
/* Other actions */
|
|
267
271
|
}
|
|
@@ -7,5 +7,5 @@ export default abstract class BaseParaNativeStakingPoolHandler extends BaseNativ
|
|
|
7
7
|
/**
|
|
8
8
|
* @todo Recheck
|
|
9
9
|
* */
|
|
10
|
-
validateYieldLeave(amount: string, address: string, fastLeave: boolean, selectedTarget?: string): Promise<TransactionError[]>;
|
|
10
|
+
validateYieldLeave(amount: string, address: string, fastLeave: boolean, selectedTarget?: string, slug?: string): Promise<TransactionError[]>;
|
|
11
11
|
}
|
|
@@ -25,10 +25,11 @@ export default class BaseParaNativeStakingPoolHandler extends BaseNativeStakingP
|
|
|
25
25
|
const {
|
|
26
26
|
address,
|
|
27
27
|
amount,
|
|
28
|
-
selectedValidators
|
|
28
|
+
selectedValidators,
|
|
29
|
+
slug
|
|
29
30
|
} = data;
|
|
30
|
-
const poolInfo = await this.getPoolInfo();
|
|
31
|
-
const poolPosition = await this.getPoolPosition(address);
|
|
31
|
+
const poolInfo = await this.getPoolInfo(slug);
|
|
32
|
+
const poolPosition = await this.getPoolPosition(address, slug);
|
|
32
33
|
const chainInfo = this.chainInfo;
|
|
33
34
|
const bnAmount = new BN(amount);
|
|
34
35
|
if (bnAmount.lte(BN_ZERO)) {
|
|
@@ -94,10 +95,10 @@ export default class BaseParaNativeStakingPoolHandler extends BaseNativeStakingP
|
|
|
94
95
|
/**
|
|
95
96
|
* @todo Recheck
|
|
96
97
|
* */
|
|
97
|
-
async validateYieldLeave(amount, address, fastLeave, selectedTarget) {
|
|
98
|
+
async validateYieldLeave(amount, address, fastLeave, selectedTarget, slug) {
|
|
98
99
|
const errors = [];
|
|
99
|
-
const poolInfo = await this.getPoolInfo();
|
|
100
|
-
const poolPosition = await this.getPoolPosition(address);
|
|
100
|
+
const poolInfo = await this.getPoolInfo(slug);
|
|
101
|
+
const poolPosition = await this.getPoolPosition(address, slug);
|
|
101
102
|
if (!poolInfo || !poolInfo.statistic || !poolPosition || fastLeave || !selectedTarget) {
|
|
102
103
|
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
103
104
|
}
|
|
@@ -13,7 +13,7 @@ export default abstract class BaseNativeStakingPoolHandler extends BasePoolHandl
|
|
|
13
13
|
getPoolReward(useAddresses: string[], callBack: (rs: EarningRewardItem) => void): Promise<VoidFunction>;
|
|
14
14
|
getPoolRewardHistory(useAddresses: string[], callBack: (rs: EarningRewardHistoryItem) => void): Promise<VoidFunction>;
|
|
15
15
|
get defaultSubmitStep(): YieldStepBaseInfo;
|
|
16
|
-
abstract createJoinExtrinsic(data: SubmitJoinNativeStaking, positionInfo?: YieldPositionInfo, bondDest?: string): Promise<[TransactionData, YieldTokenBaseInfo]>;
|
|
16
|
+
abstract createJoinExtrinsic(data: SubmitJoinNativeStaking, positionInfo?: YieldPositionInfo, bondDest?: string, netuid?: number): Promise<[TransactionData, YieldTokenBaseInfo]>;
|
|
17
17
|
protected getSubmitStep(params: OptimalYieldPathParams): Promise<YieldStepBaseInfo>;
|
|
18
18
|
handleYieldJoin(_data: SubmitYieldJoinData, path: OptimalYieldPath, currentStep: number): Promise<HandleYieldStepData>;
|
|
19
19
|
handleYieldRedeem(amount: string, address: string, selectedTarget?: string): Promise<[ExtrinsicType, TransactionData]>;
|
|
@@ -92,6 +92,7 @@ export default class BaseNativeStakingPoolHandler extends BasePoolHandler {
|
|
|
92
92
|
const {
|
|
93
93
|
address,
|
|
94
94
|
amount,
|
|
95
|
+
netuid,
|
|
95
96
|
slug,
|
|
96
97
|
targets
|
|
97
98
|
} = params;
|
|
@@ -100,7 +101,8 @@ export default class BaseNativeStakingPoolHandler extends BasePoolHandler {
|
|
|
100
101
|
amount,
|
|
101
102
|
address,
|
|
102
103
|
slug,
|
|
103
|
-
selectedValidators
|
|
104
|
+
selectedValidators,
|
|
105
|
+
netuid
|
|
104
106
|
};
|
|
105
107
|
const positionInfo = await this.getPoolPosition(address);
|
|
106
108
|
const [, fee] = await this.createJoinExtrinsic(data, positionInfo);
|
|
@@ -111,9 +113,10 @@ export default class BaseNativeStakingPoolHandler extends BasePoolHandler {
|
|
|
111
113
|
const {
|
|
112
114
|
address,
|
|
113
115
|
amount,
|
|
114
|
-
selectedValidators
|
|
116
|
+
selectedValidators,
|
|
117
|
+
slug
|
|
115
118
|
} = data;
|
|
116
|
-
const positionInfo = await this.getPoolPosition(address);
|
|
119
|
+
const positionInfo = await this.getPoolPosition(address, slug);
|
|
117
120
|
const [extrinsic] = await this.createJoinExtrinsic(data, positionInfo);
|
|
118
121
|
const bondingData = {
|
|
119
122
|
poolPosition: positionInfo,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { _ChainInfo } from '@subwallet/chain-list/types';
|
|
2
|
+
import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
|
|
3
|
+
import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
|
|
4
|
+
import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
|
|
5
|
+
import BaseParaStakingPoolHandler from '@subwallet/extension-base/services/earning-service/handlers/native-staking/base-para';
|
|
6
|
+
import { BaseYieldPositionInfo, StakeCancelWithdrawalParams, SubmitJoinNativeStaking, TransactionData, UnstakingInfo, ValidatorInfo, YieldPoolInfo, YieldPoolMethodInfo, YieldPoolType, YieldPositionInfo, YieldTokenBaseInfo } from '@subwallet/extension-base/types';
|
|
7
|
+
import { BigNumber } from 'bignumber.js';
|
|
8
|
+
export interface SubnetData {
|
|
9
|
+
netuid: number;
|
|
10
|
+
name: string;
|
|
11
|
+
symbol: string;
|
|
12
|
+
ownerHotkey: string;
|
|
13
|
+
maxAllowedValidators: number;
|
|
14
|
+
taoIn: number;
|
|
15
|
+
}
|
|
16
|
+
interface TaoStakingStakeOption {
|
|
17
|
+
owner: string;
|
|
18
|
+
amount: string;
|
|
19
|
+
rate?: BigNumber;
|
|
20
|
+
identity?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface RawDelegateState {
|
|
23
|
+
data: Array<{
|
|
24
|
+
hotkey_name: string;
|
|
25
|
+
hotkey: {
|
|
26
|
+
ss58: string;
|
|
27
|
+
};
|
|
28
|
+
stake: string;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
declare type Nominators = [Array<[number, number]>];
|
|
32
|
+
export interface TestnetBittensorDelegateInfo {
|
|
33
|
+
delegateSs58: string;
|
|
34
|
+
take: number;
|
|
35
|
+
nominators: Nominators;
|
|
36
|
+
returnPer1000: number;
|
|
37
|
+
}
|
|
38
|
+
export declare const getTaoToAlphaMapping: (substrateApi: _SubstrateApi) => Promise<Record<number, string>>;
|
|
39
|
+
export default class SubnetTaoStakingPoolHandler extends BaseParaStakingPoolHandler {
|
|
40
|
+
handleYieldWithdraw(address: string, unstakingInfo: UnstakingInfo): Promise<TransactionData>;
|
|
41
|
+
handleYieldCancelUnstake(params: StakeCancelWithdrawalParams): Promise<TransactionData>;
|
|
42
|
+
readonly type = YieldPoolType.SUBNET_STAKING;
|
|
43
|
+
slug: string;
|
|
44
|
+
protected name: string;
|
|
45
|
+
protected shortName: string;
|
|
46
|
+
subnetData: SubnetData[];
|
|
47
|
+
private isInit;
|
|
48
|
+
private bittensorCache;
|
|
49
|
+
readonly availableMethod: YieldPoolMethodInfo;
|
|
50
|
+
constructor(state: KoniState, chain: string);
|
|
51
|
+
canHandleSlug(slug: string): boolean;
|
|
52
|
+
get maintainBalance(): string;
|
|
53
|
+
private init;
|
|
54
|
+
protected getDescription(): string;
|
|
55
|
+
subscribePoolInfo(callback: (data: YieldPoolInfo) => void): Promise<VoidFunction>;
|
|
56
|
+
parseNominatorMetadata(chainInfo: _ChainInfo, address: string, delegatorState: TaoStakingStakeOption[]): Promise<Omit<YieldPositionInfo, keyof BaseYieldPositionInfo>>;
|
|
57
|
+
subscribePoolPosition(useAddresses: string[], rsCallback: (rs: YieldPositionInfo) => void): Promise<VoidFunction>;
|
|
58
|
+
private getDevnetPoolTargets;
|
|
59
|
+
private getMainnetPoolTargets;
|
|
60
|
+
getPoolTargets(): Promise<ValidatorInfo[]>;
|
|
61
|
+
createJoinExtrinsic(data: SubmitJoinNativeStaking, positionInfo?: YieldPositionInfo, bondDest?: string): Promise<[TransactionData, YieldTokenBaseInfo]>;
|
|
62
|
+
handleYieldUnstake(amount: string, address: string, selectedTarget?: string, netuid?: number): Promise<[ExtrinsicType, TransactionData]>;
|
|
63
|
+
}
|
|
64
|
+
export {};
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
// Copyright 2019-2022 @subwallet/extension-base
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
5
|
+
import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
|
|
6
|
+
import { BITTENSOR_REFRESH_STAKE_APY, BITTENSOR_REFRESH_STAKE_INFO } from '@subwallet/extension-base/constants';
|
|
7
|
+
import { getEarningStatusByNominations } from '@subwallet/extension-base/koni/api/staking/bonding/utils';
|
|
8
|
+
import BaseParaStakingPoolHandler from '@subwallet/extension-base/services/earning-service/handlers/native-staking/base-para';
|
|
9
|
+
import { BasicTxErrorType, EarningStatus, YieldPoolType } from '@subwallet/extension-base/types';
|
|
10
|
+
import { reformatAddress } from '@subwallet/extension-base/utils';
|
|
11
|
+
import BigN from 'bignumber.js';
|
|
12
|
+
import { BN, BN_TEN, BN_ZERO } from '@polkadot/util';
|
|
13
|
+
import { calculateReward } from "../../utils/index.js";
|
|
14
|
+
import { BittensorCache } from "./tao.js";
|
|
15
|
+
export const getTaoToAlphaMapping = async substrateApi => {
|
|
16
|
+
const allSubnets = (await substrateApi.api.call.subnetInfoRuntimeApi.getAllDynamicInfo()).toJSON();
|
|
17
|
+
if (!allSubnets) {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
return allSubnets.reduce((acc, subnet) => {
|
|
21
|
+
const netuid = subnet === null || subnet === void 0 ? void 0 : subnet.netuid;
|
|
22
|
+
const taoIn = subnet !== null && subnet !== void 0 && subnet.taoIn ? new BigN(subnet.taoIn) : new BigN(0);
|
|
23
|
+
const alphaIn = subnet !== null && subnet !== void 0 && subnet.alphaIn ? new BigN(subnet.alphaIn) : new BigN(0);
|
|
24
|
+
if (netuid === 0) {
|
|
25
|
+
acc[netuid] = '1';
|
|
26
|
+
} else if (alphaIn.gt(0)) {
|
|
27
|
+
acc[netuid] = taoIn.dividedBy(alphaIn).toString();
|
|
28
|
+
} else {
|
|
29
|
+
acc[netuid] = '1';
|
|
30
|
+
}
|
|
31
|
+
return acc;
|
|
32
|
+
}, {});
|
|
33
|
+
};
|
|
34
|
+
export default class SubnetTaoStakingPoolHandler extends BaseParaStakingPoolHandler {
|
|
35
|
+
/* Unimplemented function */
|
|
36
|
+
handleYieldWithdraw(address, unstakingInfo) {
|
|
37
|
+
throw new Error('Method not implemented.');
|
|
38
|
+
}
|
|
39
|
+
handleYieldCancelUnstake(params) {
|
|
40
|
+
throw new Error('Method not implemented.');
|
|
41
|
+
}
|
|
42
|
+
/* Unimplemented function */
|
|
43
|
+
|
|
44
|
+
// @ts-ignore
|
|
45
|
+
type = YieldPoolType.SUBNET_STAKING;
|
|
46
|
+
subnetData = [];
|
|
47
|
+
isInit = false;
|
|
48
|
+
availableMethod = {
|
|
49
|
+
join: true,
|
|
50
|
+
defaultUnstake: true,
|
|
51
|
+
fastUnstake: false,
|
|
52
|
+
cancelUnstake: false,
|
|
53
|
+
withdraw: false,
|
|
54
|
+
claimReward: false
|
|
55
|
+
};
|
|
56
|
+
constructor(state, chain) {
|
|
57
|
+
super(state, chain);
|
|
58
|
+
const _chainAsset = this.nativeToken;
|
|
59
|
+
const _chainInfo = this.chainInfo;
|
|
60
|
+
const symbol = _chainAsset.symbol;
|
|
61
|
+
this.slug = this.slug = `${symbol}___subnet_staking___${_chainInfo.slug}`;
|
|
62
|
+
this.name = 'Subnet Tao Staking';
|
|
63
|
+
this.shortName = 'dTAO Staking';
|
|
64
|
+
this.bittensorCache = BittensorCache.getInstance();
|
|
65
|
+
}
|
|
66
|
+
canHandleSlug(slug) {
|
|
67
|
+
return slug.startsWith(`${this.slug}__`);
|
|
68
|
+
}
|
|
69
|
+
get maintainBalance() {
|
|
70
|
+
const ed = new BN(this.nativeToken.minAmount || '0');
|
|
71
|
+
const calculateMaintainBalance = new BN(15).mul(ed).div(BN_TEN);
|
|
72
|
+
const maintainBalance = calculateMaintainBalance;
|
|
73
|
+
return maintainBalance.toString();
|
|
74
|
+
}
|
|
75
|
+
async init() {
|
|
76
|
+
try {
|
|
77
|
+
const substrateApi = await this.substrateApi.isReady;
|
|
78
|
+
const dynamicInfo = (await substrateApi.api.call.subnetInfoRuntimeApi.getAllDynamicInfo()).toJSON();
|
|
79
|
+
const subnetsInfo = (await substrateApi.api.call.subnetInfoRuntimeApi.getSubnetsInfoV2()).toJSON();
|
|
80
|
+
if (dynamicInfo && subnetsInfo) {
|
|
81
|
+
const mergedData = dynamicInfo.filter(dynInfo => dynInfo.netuid !== 0).map(dynInfo => {
|
|
82
|
+
var _dynInfo$subnetIdenti, _dynInfo$subnetIdenti2;
|
|
83
|
+
const extraInfo = subnetsInfo.find(subnet => subnet.netuid === dynInfo.netuid);
|
|
84
|
+
const nameRaw = ((_dynInfo$subnetIdenti = dynInfo.subnetIdentity) === null || _dynInfo$subnetIdenti === void 0 ? void 0 : _dynInfo$subnetIdenti.subnetName) || String.fromCharCode(...dynInfo.subnetName);
|
|
85
|
+
const identityName = (_dynInfo$subnetIdenti2 = dynInfo.subnetIdentity) !== null && _dynInfo$subnetIdenti2 !== void 0 && _dynInfo$subnetIdenti2.subnetName ? Buffer.from(dynInfo.subnetIdentity.subnetName.slice(2), 'hex').toString('utf-8') : '';
|
|
86
|
+
const formattedIdentityName = identityName ? identityName.charAt(0).toUpperCase() + identityName.slice(1).toLowerCase() : '';
|
|
87
|
+
const name = formattedIdentityName || nameRaw.charAt(0).toUpperCase() + nameRaw.slice(1);
|
|
88
|
+
const symbol = new TextDecoder('utf-8').decode(Uint8Array.from(dynInfo.tokenSymbol));
|
|
89
|
+
return {
|
|
90
|
+
netuid: dynInfo.netuid,
|
|
91
|
+
name,
|
|
92
|
+
symbol,
|
|
93
|
+
ownerHotkey: dynInfo.ownerHotkey,
|
|
94
|
+
maxAllowedValidators: extraInfo ? extraInfo.maxAllowedValidators : 0,
|
|
95
|
+
taoIn: dynInfo.taoIn
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
this.subnetData = mergedData;
|
|
99
|
+
this.isInit = true;
|
|
100
|
+
}
|
|
101
|
+
} catch (err) {
|
|
102
|
+
console.error(err);
|
|
103
|
+
this.isInit = false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
getDescription() {
|
|
107
|
+
return 'Stake TAO to earn yield on dTAO';
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Subscribe pool info */
|
|
111
|
+
|
|
112
|
+
async subscribePoolInfo(callback) {
|
|
113
|
+
if (!this.isInit) {
|
|
114
|
+
await this.init();
|
|
115
|
+
}
|
|
116
|
+
let cancel = false;
|
|
117
|
+
const substrateApi = await this.substrateApi.isReady;
|
|
118
|
+
const updateStakingInfo = async () => {
|
|
119
|
+
try {
|
|
120
|
+
if (cancel) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const minDelegatorStake = (await substrateApi.api.query.subtensorModule.nominatorMinRequiredStake()).toPrimitive() || 0;
|
|
124
|
+
const BNminDelegatorStake = new BigN(minDelegatorStake.toString());
|
|
125
|
+
this.subnetData.forEach(subnet => {
|
|
126
|
+
const netuid = subnet.netuid.toString().padStart(2, '0');
|
|
127
|
+
const subnetSlug = `${this.slug}__subnet_${netuid.padStart(2, '0')}`;
|
|
128
|
+
const subnetName = `${subnet.name || 'Unknown'} ${netuid}`;
|
|
129
|
+
const bnTaoIn = new BN(subnet.taoIn);
|
|
130
|
+
const data = {
|
|
131
|
+
...this.baseInfo,
|
|
132
|
+
type: this.type,
|
|
133
|
+
slug: subnetSlug,
|
|
134
|
+
metadata: {
|
|
135
|
+
...this.metadataInfo,
|
|
136
|
+
name: subnetName,
|
|
137
|
+
shortName: subnetName,
|
|
138
|
+
description: this.getDescription(),
|
|
139
|
+
subnetData: {
|
|
140
|
+
netuid: subnet.netuid,
|
|
141
|
+
subnetSymbol: subnet.symbol || 'dTAO'
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
statistic: {
|
|
145
|
+
assetEarning: [{
|
|
146
|
+
slug: this.nativeToken.slug
|
|
147
|
+
}],
|
|
148
|
+
maxCandidatePerFarmer: subnet.maxAllowedValidators,
|
|
149
|
+
maxWithdrawalRequestPerFarmer: 1,
|
|
150
|
+
earningThreshold: {
|
|
151
|
+
join: BNminDelegatorStake.toString(),
|
|
152
|
+
defaultUnstake: '0',
|
|
153
|
+
fastUnstake: '0'
|
|
154
|
+
},
|
|
155
|
+
eraTime: 24,
|
|
156
|
+
era: 0,
|
|
157
|
+
unstakingPeriod: 1.2,
|
|
158
|
+
tvl: bnTaoIn.toString()
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
callback(data);
|
|
162
|
+
});
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.error('Error updating staking info:', error);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const subscribeStakingMetadataInterval = () => {
|
|
168
|
+
updateStakingInfo().catch(console.error);
|
|
169
|
+
};
|
|
170
|
+
await substrateApi.isReady;
|
|
171
|
+
subscribeStakingMetadataInterval();
|
|
172
|
+
const interval = setInterval(subscribeStakingMetadataInterval, BITTENSOR_REFRESH_STAKE_APY);
|
|
173
|
+
return () => {
|
|
174
|
+
cancel = true;
|
|
175
|
+
clearInterval(interval);
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* Subscribe pool position */
|
|
180
|
+
|
|
181
|
+
async parseNominatorMetadata(chainInfo, address, delegatorState) {
|
|
182
|
+
const nominationList = [];
|
|
183
|
+
const getMinDelegatorStake = this.substrateApi.api.query.subtensorModule.nominatorMinRequiredStake();
|
|
184
|
+
const minDelegatorStake = (await getMinDelegatorStake).toString();
|
|
185
|
+
let allActiveStake = BN_ZERO;
|
|
186
|
+
for (const delegate of delegatorState) {
|
|
187
|
+
const stake = new BigN(delegate.amount);
|
|
188
|
+
const originActiveStake = stake.multipliedBy(delegate.rate || new BigN(1)).toFixed(0).toString();
|
|
189
|
+
const bnActiveStake = new BN(originActiveStake);
|
|
190
|
+
if (bnActiveStake.gt(BN_ZERO)) {
|
|
191
|
+
const delegationStatus = EarningStatus.EARNING_REWARD;
|
|
192
|
+
allActiveStake = allActiveStake.add(bnActiveStake);
|
|
193
|
+
nominationList.push({
|
|
194
|
+
status: delegationStatus,
|
|
195
|
+
chain: chainInfo.slug,
|
|
196
|
+
validatorAddress: delegate.owner,
|
|
197
|
+
activeStake: delegate.amount,
|
|
198
|
+
validatorMinStake: minDelegatorStake,
|
|
199
|
+
originActiveStake: originActiveStake,
|
|
200
|
+
validatorIdentity: delegate.identity
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const stakingStatus = getEarningStatusByNominations(allActiveStake, nominationList);
|
|
205
|
+
return {
|
|
206
|
+
status: stakingStatus,
|
|
207
|
+
balanceToken: this.nativeToken.slug,
|
|
208
|
+
totalStake: allActiveStake.toString(),
|
|
209
|
+
activeStake: allActiveStake.toString(),
|
|
210
|
+
unstakeBalance: '0',
|
|
211
|
+
isBondedBefore: true,
|
|
212
|
+
nominations: nominationList,
|
|
213
|
+
unstakings: []
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
async subscribePoolPosition(useAddresses, rsCallback) {
|
|
217
|
+
if (!this.isInit) {
|
|
218
|
+
await this.init();
|
|
219
|
+
}
|
|
220
|
+
let cancel = false;
|
|
221
|
+
const substrateApi = await this.substrateApi.isReady;
|
|
222
|
+
const defaultInfo = this.baseInfo;
|
|
223
|
+
const chainInfo = this.chainInfo;
|
|
224
|
+
const _delegateInfo = await this.bittensorCache.get();
|
|
225
|
+
const getPoolPosition = async () => {
|
|
226
|
+
const rawDelegateStateInfos = await Promise.all(useAddresses.map(async address => (await substrateApi.api.call.stakeInfoRuntimeApi.getStakeInfoForColdkey(address)).toJSON()));
|
|
227
|
+
const price = await getTaoToAlphaMapping(this.substrateApi);
|
|
228
|
+
if (rawDelegateStateInfos && rawDelegateStateInfos.length > 0) {
|
|
229
|
+
rawDelegateStateInfos.forEach((rawDelegateStateInfo, i) => {
|
|
230
|
+
const owner = reformatAddress(useAddresses[i], 42);
|
|
231
|
+
const delegateStateInfo = rawDelegateStateInfo;
|
|
232
|
+
const subnetPositions = {};
|
|
233
|
+
for (const delegate of delegateStateInfo) {
|
|
234
|
+
const hotkey = delegate.hotkey;
|
|
235
|
+
const netuid = delegate.netuid;
|
|
236
|
+
const stake = new BigN(delegate.stake);
|
|
237
|
+
const taoToAlphaPrice = new BigN(price[netuid]);
|
|
238
|
+
if (!subnetPositions[netuid]) {
|
|
239
|
+
subnetPositions[netuid] = {
|
|
240
|
+
delegatorState: [],
|
|
241
|
+
totalBalance: BN_ZERO,
|
|
242
|
+
originalTotalStake: BN_ZERO
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
let identity = '';
|
|
246
|
+
if (_delegateInfo) {
|
|
247
|
+
const delegateInfo = _delegateInfo.data.find(info => info.hotkey.ss58 === hotkey);
|
|
248
|
+
identity = delegateInfo ? delegateInfo.name : '';
|
|
249
|
+
}
|
|
250
|
+
subnetPositions[netuid].delegatorState.push({
|
|
251
|
+
owner: hotkey,
|
|
252
|
+
amount: stake.toString(),
|
|
253
|
+
rate: taoToAlphaPrice,
|
|
254
|
+
identity: identity
|
|
255
|
+
});
|
|
256
|
+
subnetPositions[netuid].totalBalance = subnetPositions[netuid].totalBalance.add(new BN(stake.toString()));
|
|
257
|
+
subnetPositions[netuid].originalTotalStake = subnetPositions[netuid].originalTotalStake.add(new BN(stake.toString()));
|
|
258
|
+
}
|
|
259
|
+
Object.values(this.subnetData).forEach(subnet => {
|
|
260
|
+
const netuid = subnet.netuid;
|
|
261
|
+
const subnetSlug = `${this.slug}__subnet_${netuid.toString().padStart(2, '0')}`;
|
|
262
|
+
const subnetName = `${subnet.name || 'Unknown'} ${netuid}`;
|
|
263
|
+
const subnetSymbol = subnet.symbol || 'dTAO';
|
|
264
|
+
const {
|
|
265
|
+
delegatorState = [],
|
|
266
|
+
originalTotalStake = BN_ZERO
|
|
267
|
+
} = subnetPositions[netuid] || {};
|
|
268
|
+
if (delegatorState.length > 0) {
|
|
269
|
+
this.parseNominatorMetadata(chainInfo, owner, delegatorState).then(nominatorMetadata => {
|
|
270
|
+
rsCallback({
|
|
271
|
+
...defaultInfo,
|
|
272
|
+
...nominatorMetadata,
|
|
273
|
+
address: owner,
|
|
274
|
+
type: this.type,
|
|
275
|
+
slug: subnetSlug,
|
|
276
|
+
subnetData: {
|
|
277
|
+
subnetSymbol,
|
|
278
|
+
subnetShortName: subnetName,
|
|
279
|
+
originalTotalStake: originalTotalStake.toString()
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
}).catch(console.error);
|
|
283
|
+
} else {
|
|
284
|
+
rsCallback({
|
|
285
|
+
...defaultInfo,
|
|
286
|
+
type: this.type,
|
|
287
|
+
address: owner,
|
|
288
|
+
balanceToken: this.nativeToken.slug,
|
|
289
|
+
totalStake: '0',
|
|
290
|
+
activeStake: '0',
|
|
291
|
+
unstakeBalance: '0',
|
|
292
|
+
status: EarningStatus.NOT_STAKING,
|
|
293
|
+
isBondedBefore: false,
|
|
294
|
+
nominations: [],
|
|
295
|
+
unstakings: [],
|
|
296
|
+
slug: subnetSlug,
|
|
297
|
+
subnetData: {
|
|
298
|
+
subnetSymbol,
|
|
299
|
+
subnetShortName: subnetName,
|
|
300
|
+
originalTotalStake: '0'
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
const getStakingPositionInterval = async () => {
|
|
309
|
+
if (cancel) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
await getPoolPosition();
|
|
313
|
+
};
|
|
314
|
+
getStakingPositionInterval().catch(console.error);
|
|
315
|
+
const intervalId = setInterval(() => {
|
|
316
|
+
getStakingPositionInterval().catch(console.error);
|
|
317
|
+
}, BITTENSOR_REFRESH_STAKE_INFO);
|
|
318
|
+
return () => {
|
|
319
|
+
cancel = true;
|
|
320
|
+
clearInterval(intervalId);
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/* Subscribe pool position */
|
|
325
|
+
|
|
326
|
+
/* Get pool targets */
|
|
327
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
328
|
+
async getDevnetPoolTargets() {
|
|
329
|
+
const testnetDelegate = (await this.substrateApi.api.call.delegateInfoRuntimeApi.getDelegates()).toJSON();
|
|
330
|
+
const getNominatorMinRequiredStake = this.substrateApi.api.query.subtensorModule.nominatorMinRequiredStake();
|
|
331
|
+
const nominatorMinRequiredStake = (await getNominatorMinRequiredStake).toString();
|
|
332
|
+
const bnMinBond = new BN(nominatorMinRequiredStake);
|
|
333
|
+
const filteredDelegates = testnetDelegate.filter(delegate => {
|
|
334
|
+
return delegate.returnPer1000 !== 0;
|
|
335
|
+
});
|
|
336
|
+
return filteredDelegates.map(delegate => ({
|
|
337
|
+
address: delegate.delegateSs58,
|
|
338
|
+
totalStake: '0',
|
|
339
|
+
ownStake: '0',
|
|
340
|
+
otherStake: '0',
|
|
341
|
+
minBond: bnMinBond.toString(),
|
|
342
|
+
nominatorCount: delegate.nominators.length,
|
|
343
|
+
commission: delegate.take / 1000,
|
|
344
|
+
blocked: false,
|
|
345
|
+
isVerified: false,
|
|
346
|
+
chain: this.chain,
|
|
347
|
+
isCrowded: false
|
|
348
|
+
}));
|
|
349
|
+
}
|
|
350
|
+
async getMainnetPoolTargets() {
|
|
351
|
+
const _topValidator = await this.bittensorCache.get();
|
|
352
|
+
const topValidator = _topValidator;
|
|
353
|
+
const getNominatorMinRequiredStake = this.substrateApi.api.query.subtensorModule.nominatorMinRequiredStake();
|
|
354
|
+
const nominatorMinRequiredStake = (await getNominatorMinRequiredStake).toString();
|
|
355
|
+
const bnMinBond = new BN(nominatorMinRequiredStake);
|
|
356
|
+
const validatorList = topValidator.data;
|
|
357
|
+
const validatorAddresses = Object.keys(validatorList);
|
|
358
|
+
const results = await Promise.all(validatorAddresses.map(i => {
|
|
359
|
+
const address = validatorList[i].hotkey.ss58;
|
|
360
|
+
const bnTotalStake = new BN(validatorList[i].stake);
|
|
361
|
+
const bnOwnStake = new BN(validatorList[i].validator_stake);
|
|
362
|
+
const otherStake = bnTotalStake.sub(bnOwnStake);
|
|
363
|
+
const nominatorCount = validatorList[i].nominators;
|
|
364
|
+
const commission = validatorList[i].take;
|
|
365
|
+
const roundedCommission = (parseFloat(commission) * 100).toFixed(0);
|
|
366
|
+
const apr = (parseFloat(validatorList[i].apr) / 10 ** 9 * 100).toFixed(2);
|
|
367
|
+
const apyCalculate = calculateReward(parseFloat(apr));
|
|
368
|
+
const name = validatorList[i].name || address;
|
|
369
|
+
return {
|
|
370
|
+
address: address,
|
|
371
|
+
totalStake: bnTotalStake.toString(),
|
|
372
|
+
ownStake: bnOwnStake.toString(),
|
|
373
|
+
otherStake: otherStake.toString(),
|
|
374
|
+
minBond: bnMinBond.toString(),
|
|
375
|
+
nominatorCount: nominatorCount,
|
|
376
|
+
commission: roundedCommission,
|
|
377
|
+
expectedReturn: apyCalculate.apy,
|
|
378
|
+
blocked: false,
|
|
379
|
+
isVerified: false,
|
|
380
|
+
chain: this.chain,
|
|
381
|
+
isCrowded: false,
|
|
382
|
+
identity: name
|
|
383
|
+
};
|
|
384
|
+
}));
|
|
385
|
+
return results;
|
|
386
|
+
}
|
|
387
|
+
async getPoolTargets() {
|
|
388
|
+
if (!this.isInit) {
|
|
389
|
+
await this.init();
|
|
390
|
+
}
|
|
391
|
+
if (this.chain === 'bittensor') {
|
|
392
|
+
return this.getMainnetPoolTargets();
|
|
393
|
+
} else {
|
|
394
|
+
return this.getDevnetPoolTargets();
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/* Get pool targets */
|
|
399
|
+
|
|
400
|
+
/* Join pool action */
|
|
401
|
+
|
|
402
|
+
async createJoinExtrinsic(data, positionInfo, bondDest = 'Staked') {
|
|
403
|
+
const {
|
|
404
|
+
amount,
|
|
405
|
+
netuid,
|
|
406
|
+
selectedValidators: targetValidators
|
|
407
|
+
} = data;
|
|
408
|
+
const chainApi = await this.substrateApi.isReady;
|
|
409
|
+
const binaryAmount = new BN(amount);
|
|
410
|
+
const selectedValidatorInfo = targetValidators[0];
|
|
411
|
+
const hotkey = selectedValidatorInfo.address;
|
|
412
|
+
const extrinsic = chainApi.api.tx.subtensorModule.addStake(hotkey, netuid, binaryAmount);
|
|
413
|
+
return [extrinsic, {
|
|
414
|
+
slug: this.nativeToken.slug,
|
|
415
|
+
amount: '0'
|
|
416
|
+
}];
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/* Join pool action */
|
|
420
|
+
|
|
421
|
+
/* Leave pool action */
|
|
422
|
+
|
|
423
|
+
async handleYieldUnstake(amount, address, selectedTarget, netuid) {
|
|
424
|
+
const apiPromise = await this.substrateApi.isReady;
|
|
425
|
+
const binaryAmount = new BN(amount);
|
|
426
|
+
if (!selectedTarget) {
|
|
427
|
+
return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS));
|
|
428
|
+
}
|
|
429
|
+
const extrinsic = apiPromise.api.tx.subtensorModule.removeStake(selectedTarget, netuid, binaryAmount);
|
|
430
|
+
return [ExtrinsicType.STAKING_UNBOND, extrinsic];
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/* Leave pool action */
|
|
434
|
+
}
|
|
@@ -3,3 +3,4 @@ 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
5
|
export { default as TaoNativeStakingPoolHandler } from './tao';
|
|
6
|
+
export { default as SubnetTaoStakingPoolHandler } from './dtao';
|
|
@@ -5,4 +5,5 @@ export { default as AmplitudeNativeStakingPoolHandler } from "./amplitude.js";
|
|
|
5
5
|
export { default as AstarNativeStakingPoolHandler } from "./astar.js";
|
|
6
6
|
export { default as RelayNativeStakingPoolHandler } from "./relay-chain.js";
|
|
7
7
|
export { default as ParaNativeStakingPoolHandler } from "./para-chain.js";
|
|
8
|
-
export { default as TaoNativeStakingPoolHandler } from "./tao.js";
|
|
8
|
+
export { default as TaoNativeStakingPoolHandler } from "./tao.js";
|
|
9
|
+
export { default as SubnetTaoStakingPoolHandler } from "./dtao.js";
|