@subwallet/extension-base 1.0.7-1 → 1.0.8-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 +6 -4
- package/background/KoniTypes.js +1 -0
- package/background/errors/TransactionError.js +5 -1
- package/cjs/background/KoniTypes.js +1 -0
- package/cjs/background/errors/TransactionError.js +4 -0
- package/cjs/constants/index.js +6 -3
- package/cjs/koni/api/dotsama/balance.js +2 -1
- package/cjs/koni/api/dotsama/crowdloan.js +1 -1
- package/cjs/koni/api/dotsama/transfer.js +2 -2
- package/cjs/koni/api/staking/bonding/astar.js +5 -4
- package/cjs/koni/api/staking/bonding/relayChain.js +12 -3
- package/cjs/koni/api/staking/bonding/utils.js +7 -0
- package/cjs/koni/api/xcm/polkadotXcm.js +18 -37
- package/cjs/koni/api/xcm/utils.js +78 -11
- package/cjs/koni/api/xcm/xTokens.js +4 -33
- package/cjs/koni/api/xcm/xcmPallet.js +4 -36
- package/cjs/koni/background/handlers/Extension.js +179 -97
- package/cjs/koni/background/handlers/State.js +1 -1
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/chain-service/constants.js +8 -6
- package/cjs/services/chain-service/index.js +19 -15
- package/cjs/services/chain-service/utils.js +1 -5
- package/cjs/services/transaction-service/helpers/index.js +45 -2
- package/cjs/services/transaction-service/index.js +58 -24
- package/cjs/utils/number.js +112 -0
- package/constants/index.d.ts +1 -0
- package/constants/index.js +1 -0
- package/koni/api/dotsama/balance.js +2 -1
- package/koni/api/dotsama/crowdloan.js +2 -2
- package/koni/api/dotsama/transfer.js +2 -2
- package/koni/api/staking/bonding/astar.js +5 -4
- package/koni/api/staking/bonding/relayChain.js +13 -4
- package/koni/api/staking/bonding/utils.d.ts +5 -0
- package/koni/api/staking/bonding/utils.js +6 -0
- package/koni/api/xcm/polkadotXcm.js +20 -39
- package/koni/api/xcm/utils.d.ts +36 -3
- package/koni/api/xcm/utils.js +72 -11
- package/koni/api/xcm/xTokens.js +6 -35
- package/koni/api/xcm/xcmPallet.js +5 -35
- package/koni/background/handlers/Extension.js +109 -29
- package/koni/background/handlers/State.js +2 -2
- package/package.json +13 -8
- package/packageInfo.js +1 -1
- package/services/chain-service/constants.d.ts +1 -0
- package/services/chain-service/constants.js +8 -7
- package/services/chain-service/index.js +13 -8
- package/services/chain-service/types.d.ts +8 -0
- package/services/chain-service/utils.d.ts +0 -1
- package/services/chain-service/utils.js +1 -4
- package/services/transaction-service/helpers/index.d.ts +2 -0
- package/services/transaction-service/helpers/index.js +42 -0
- package/services/transaction-service/index.js +54 -20
- package/services/transaction-service/types.d.ts +2 -2
- package/utils/number.d.ts +9 -0
- package/utils/number.js +100 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
5
5
|
import { StakingStatus, StakingTxErrorType, StakingType, UnstakingStatus } from '@subwallet/extension-base/background/KoniTypes';
|
|
6
|
-
import { calculateAlephZeroValidatorReturn, calculateChainStakedReturn, calculateInflation, calculateValidatorStakedReturn, getCommission, parseIdentity, parsePoolStashAddress, transformPoolName } from '@subwallet/extension-base/koni/api/staking/bonding/utils';
|
|
6
|
+
import { calculateAlephZeroValidatorReturn, calculateChainStakedReturn, calculateInflation, calculateTernoaValidatorReturn, calculateValidatorStakedReturn, getCommission, parseIdentity, parsePoolStashAddress, transformPoolName } from '@subwallet/extension-base/koni/api/staking/bonding/utils';
|
|
7
7
|
import { _STAKING_CHAIN_GROUP, _STAKING_ERA_LENGTH_MAP } from '@subwallet/extension-base/services/chain-service/constants';
|
|
8
8
|
import { _getChainSubstrateAddressPrefix } from '@subwallet/extension-base/services/chain-service/utils';
|
|
9
9
|
import { reformatAddress } from '@subwallet/extension-base/utils';
|
|
@@ -138,7 +138,7 @@ export async function getRelayChainStakingMetadata(chainInfo, substrateApi) {
|
|
|
138
138
|
chain,
|
|
139
139
|
type: StakingType.NOMINATED,
|
|
140
140
|
era: parseInt(currentEra),
|
|
141
|
-
expectedReturn,
|
|
141
|
+
expectedReturn: !_STAKING_CHAIN_GROUP.ternoa.includes(chain) ? expectedReturn : undefined,
|
|
142
142
|
// in %, annually
|
|
143
143
|
inflation,
|
|
144
144
|
minStake: minStake.toString(),
|
|
@@ -477,7 +477,8 @@ export async function getRelayValidatorsInfo(chain, substrateApi, decimals, chai
|
|
|
477
477
|
const currentEra = _era.toString();
|
|
478
478
|
const allValidators = [];
|
|
479
479
|
const validatorInfoList = [];
|
|
480
|
-
const [_totalEraStake, _eraStakers, _minBond] = await Promise.all([chainApi.api.query.staking.erasTotalStake(parseInt(currentEra)), chainApi.api.query.staking.erasStakers.entries(parseInt(currentEra)), chainApi.api.query.staking.minNominatorBond()]);
|
|
480
|
+
const [_totalEraStake, _eraStakers, _minBond, _stakingRewards] = await Promise.all([chainApi.api.query.staking.erasTotalStake(parseInt(currentEra)), chainApi.api.query.staking.erasStakers.entries(parseInt(currentEra)), chainApi.api.query.staking.minNominatorBond(), chainApi.api.query.stakingRewards && chainApi.api.query.stakingRewards.data()]);
|
|
481
|
+
const stakingRewards = _stakingRewards === null || _stakingRewards === void 0 ? void 0 : _stakingRewards.toPrimitive();
|
|
481
482
|
const maxNominatorRewarded = chainApi.api.consts.staking.maxNominatorRewardedPerValidator.toString();
|
|
482
483
|
const bnTotalEraStake = new BN(_totalEraStake.toString());
|
|
483
484
|
const eraStakers = _eraStakers;
|
|
@@ -540,7 +541,15 @@ export async function getRelayValidatorsInfo(chain, substrateApi, decimals, chai
|
|
|
540
541
|
for (const validator of validatorInfoList) {
|
|
541
542
|
const commission = extraInfoMap[validator.address].commission;
|
|
542
543
|
const bnValidatorStake = totalStakeMap[validator.address].div(bnDecimals);
|
|
543
|
-
|
|
544
|
+
if (_STAKING_CHAIN_GROUP.aleph.includes(chain)) {
|
|
545
|
+
validator.expectedReturn = calculateAlephZeroValidatorReturn(chainStakingMetadata.expectedReturn, getCommission(commission));
|
|
546
|
+
} else if (_STAKING_CHAIN_GROUP.ternoa.includes(chain)) {
|
|
547
|
+
const rewardPerValidator = new BN(stakingRewards.sessionExtraRewardPayout).divn(allValidators.length).div(bnDecimals);
|
|
548
|
+
const validatorStake = totalStakeMap[validator.address].div(bnDecimals).toNumber();
|
|
549
|
+
validator.expectedReturn = calculateTernoaValidatorReturn(rewardPerValidator.toNumber(), validatorStake, getCommission(commission));
|
|
550
|
+
} else {
|
|
551
|
+
validator.expectedReturn = calculateValidatorStakedReturn(chainStakingMetadata.expectedReturn, bnValidatorStake, bnAvgStake, getCommission(commission));
|
|
552
|
+
}
|
|
544
553
|
validator.commission = parseFloat(commission.split('%')[0]);
|
|
545
554
|
validator.blocked = extraInfoMap[validator.address].blocked;
|
|
546
555
|
validator.identity = extraInfoMap[validator.address].identity;
|
|
@@ -102,6 +102,10 @@ export interface Unlocking {
|
|
|
102
102
|
remainingEras: BN;
|
|
103
103
|
value: BN;
|
|
104
104
|
}
|
|
105
|
+
export interface TernoaStakingRewardsStakingRewardsData {
|
|
106
|
+
sessionEraPayout: string;
|
|
107
|
+
sessionExtraRewardPayout: string;
|
|
108
|
+
}
|
|
105
109
|
export declare function parsePoolStashAddress(api: ApiPromise, index: number, poolId: number, poolsPalletId: string): string;
|
|
106
110
|
export declare function transformPoolName(input: string): string;
|
|
107
111
|
export declare function parseIdentity(identityInfo: PalletIdentityRegistration | null): string | undefined;
|
|
@@ -111,6 +115,7 @@ export declare function calcInflationRewardCurve(minInflation: number, stakedFra
|
|
|
111
115
|
export declare function calculateInflation(totalEraStake: BN, totalIssuance: BN, numAuctions: number, networkKey: string): number;
|
|
112
116
|
export declare function calculateChainStakedReturn(inflation: number, totalEraStake: BN, totalIssuance: BN, networkKey: string): number;
|
|
113
117
|
export declare function calculateAlephZeroValidatorReturn(chainStakedReturn: number, commission: number): number;
|
|
118
|
+
export declare function calculateTernoaValidatorReturn(rewardPerValidator: number, validatorStake: number, commission: number): number;
|
|
114
119
|
export declare function calculateValidatorStakedReturn(chainStakedReturn: number, totalValidatorStake: BN, avgStake: BN, commission: number): number;
|
|
115
120
|
export declare function getCommission(commissionString: string): number;
|
|
116
121
|
export interface InflationConfig {
|
|
@@ -86,6 +86,12 @@ export function calculateChainStakedReturn(inflation, totalEraStake, totalIssuan
|
|
|
86
86
|
export function calculateAlephZeroValidatorReturn(chainStakedReturn, commission) {
|
|
87
87
|
return chainStakedReturn * (100 - commission) / 100;
|
|
88
88
|
}
|
|
89
|
+
export function calculateTernoaValidatorReturn(rewardPerValidator, validatorStake, commission) {
|
|
90
|
+
const percentRewardForNominators = (100 - commission) / 100;
|
|
91
|
+
const rewardForNominators = rewardPerValidator * percentRewardForNominators;
|
|
92
|
+
const stakeRatio = rewardForNominators / validatorStake;
|
|
93
|
+
return stakeRatio * 365 * 100;
|
|
94
|
+
}
|
|
89
95
|
export function calculateValidatorStakedReturn(chainStakedReturn, totalValidatorStake, avgStake, commission) {
|
|
90
96
|
const bnAdjusted = avgStake.mul(BN_HUNDRED).div(totalValidatorStake);
|
|
91
97
|
const adjusted = bnAdjusted.toNumber() * chainStakedReturn;
|
|
@@ -1,49 +1,30 @@
|
|
|
1
1
|
// Copyright 2019-2022 @subwallet/extension-base
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
import { getBeneficiary, getDestWeight } from '@subwallet/extension-base/koni/api/xcm/utils';
|
|
5
|
-
import {
|
|
6
|
-
function getDestinationChainLocation(destinationChainInfo) {
|
|
7
|
-
if (_isSubstrateParaChain(destinationChainInfo)) {
|
|
8
|
-
return {
|
|
9
|
-
V1: {
|
|
10
|
-
parents: 1,
|
|
11
|
-
interior: {
|
|
12
|
-
X1: {
|
|
13
|
-
Parachain: _getSubstrateParaId(destinationChainInfo)
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
return {
|
|
20
|
-
// to relaychain by default
|
|
21
|
-
V1: {
|
|
22
|
-
parents: 1,
|
|
23
|
-
interior: 'Here'
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
function getAssetLocation(tokenInfo, sendingValue) {
|
|
28
|
-
const multilocation = _getXcmAssetMultilocation(tokenInfo);
|
|
29
|
-
return {
|
|
30
|
-
V1: [{
|
|
31
|
-
id: multilocation,
|
|
32
|
-
fun: {
|
|
33
|
-
Fungible: sendingValue
|
|
34
|
-
}
|
|
35
|
-
}]
|
|
36
|
-
};
|
|
37
|
-
}
|
|
4
|
+
import { getBeneficiary, getDestinationChainLocation, getDestWeight, getTokenLocation } from '@subwallet/extension-base/koni/api/xcm/utils';
|
|
5
|
+
import { _isNativeToken, _isSubstrateRelayChain } from '@subwallet/extension-base/services/chain-service/utils';
|
|
38
6
|
export function getExtrinsicByPolkadotXcmPallet(tokenInfo, originChainInfo, destinationChainInfo, recipientAddress, value, api) {
|
|
39
7
|
const weightParam = getDestWeight();
|
|
40
|
-
const beneficiary = getBeneficiary(
|
|
41
|
-
const destination = getDestinationChainLocation(destinationChainInfo);
|
|
42
|
-
|
|
8
|
+
const beneficiary = getBeneficiary(destinationChainInfo, recipientAddress);
|
|
9
|
+
const destination = getDestinationChainLocation(originChainInfo, destinationChainInfo);
|
|
10
|
+
let assetLocation = getTokenLocation(tokenInfo, value);
|
|
43
11
|
let method = 'limitedReserveTransferAssets';
|
|
44
|
-
if (['astar', 'shiden'].includes(originChainInfo.slug)) {
|
|
12
|
+
if (['astar', 'shiden'].includes(originChainInfo.slug) && !_isNativeToken(tokenInfo)) {
|
|
45
13
|
method = 'limitedReserveWithdrawAssets';
|
|
46
|
-
} else if (_isSubstrateRelayChain(destinationChainInfo)) {
|
|
14
|
+
} else if (['statemint', 'statemine'].includes(originChainInfo.slug) && _isSubstrateRelayChain(destinationChainInfo)) {
|
|
15
|
+
assetLocation = {
|
|
16
|
+
V1: [{
|
|
17
|
+
id: {
|
|
18
|
+
Concrete: {
|
|
19
|
+
parents: 1,
|
|
20
|
+
interior: 'Here'
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
fun: {
|
|
24
|
+
Fungible: value
|
|
25
|
+
}
|
|
26
|
+
}]
|
|
27
|
+
};
|
|
47
28
|
method = 'limitedTeleportAssets';
|
|
48
29
|
}
|
|
49
30
|
return api.tx.polkadotXcm[method](destination, beneficiary, assetLocation, 0,
|
package/koni/api/xcm/utils.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { _ChainInfo } from '@subwallet/chain-list/types';
|
|
1
|
+
import { _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types';
|
|
2
2
|
export declare const FOUR_INSTRUCTIONS_WEIGHT = 5000000000;
|
|
3
3
|
export declare const FOUR_INSTRUCTIONS_LIMITED_WEIGHT: {
|
|
4
4
|
Limited: number;
|
|
5
5
|
};
|
|
6
|
-
export declare function getReceiverLocation(
|
|
7
|
-
export declare function getBeneficiary(
|
|
6
|
+
export declare function getReceiverLocation(destinationChainInfo: _ChainInfo, toAddress: string, version?: string): Record<string, any>;
|
|
7
|
+
export declare function getBeneficiary(destinationChainInfo: _ChainInfo, recipientAddress: string, version?: string): {
|
|
8
8
|
[x: string]: {
|
|
9
9
|
parents: number;
|
|
10
10
|
interior: {
|
|
@@ -13,3 +13,36 @@ export declare function getBeneficiary(originChainInfo: _ChainInfo, destinationC
|
|
|
13
13
|
};
|
|
14
14
|
};
|
|
15
15
|
export declare function getDestWeight(): string;
|
|
16
|
+
export declare function getTokenLocation(tokenInfo: _ChainAsset, sendingValue: string, version?: string): {
|
|
17
|
+
[x: string]: {
|
|
18
|
+
id: Record<string, any>;
|
|
19
|
+
fun: {
|
|
20
|
+
Fungible: string;
|
|
21
|
+
};
|
|
22
|
+
}[];
|
|
23
|
+
};
|
|
24
|
+
export declare function getDestMultilocation(destinationChainInfo: _ChainInfo, recipient: string, version?: string): {
|
|
25
|
+
[x: string]: {
|
|
26
|
+
parents: number;
|
|
27
|
+
interior: {
|
|
28
|
+
X2: Record<string, any>[];
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
} | {
|
|
32
|
+
[x: string]: {
|
|
33
|
+
parents: number;
|
|
34
|
+
interior: {
|
|
35
|
+
X1: Record<string, any>;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
export declare function getDestinationChainLocation(originChainInfo: _ChainInfo, destinationChainInfo: _ChainInfo, version?: string): {
|
|
40
|
+
[x: string]: {
|
|
41
|
+
parents: number;
|
|
42
|
+
interior: string | {
|
|
43
|
+
X1: {
|
|
44
|
+
Parachain: number;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
};
|
package/koni/api/xcm/utils.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import { COMMON_CHAIN_SLUGS } from '@subwallet/chain-list';
|
|
5
|
-
import { _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils';
|
|
5
|
+
import { _getSubstrateParaId, _getXcmAssetMultilocation, _isChainEvmCompatible, _isNativeToken, _isSubstrateParaChain, _isSubstrateRelayChain } from '@subwallet/extension-base/services/chain-service/utils';
|
|
6
6
|
import { decodeAddress, evmToAddress } from '@polkadot/util-crypto';
|
|
7
7
|
export const FOUR_INSTRUCTIONS_WEIGHT = 5000000000;
|
|
8
8
|
export const FOUR_INSTRUCTIONS_LIMITED_WEIGHT = {
|
|
@@ -11,13 +11,14 @@ export const FOUR_INSTRUCTIONS_LIMITED_WEIGHT = {
|
|
|
11
11
|
|
|
12
12
|
// get multilocation for destination chain from a parachain
|
|
13
13
|
|
|
14
|
-
export function getReceiverLocation(
|
|
14
|
+
export function getReceiverLocation(destinationChainInfo, toAddress, version) {
|
|
15
|
+
const network = version && version === 'V3' ? undefined : 'Any';
|
|
15
16
|
if (destinationChainInfo.slug === COMMON_CHAIN_SLUGS.ASTAR_EVM) {
|
|
16
17
|
const ss58Address = evmToAddress(toAddress, 2006); // TODO: shouldn't pass addressPrefix directly
|
|
17
18
|
|
|
18
19
|
return {
|
|
19
20
|
AccountId32: {
|
|
20
|
-
network
|
|
21
|
+
network,
|
|
21
22
|
id: decodeAddress(ss58Address)
|
|
22
23
|
}
|
|
23
24
|
};
|
|
@@ -25,20 +26,20 @@ export function getReceiverLocation(originChainInfo, destinationChainInfo, toAdd
|
|
|
25
26
|
if (_isChainEvmCompatible(destinationChainInfo)) {
|
|
26
27
|
return {
|
|
27
28
|
AccountKey20: {
|
|
28
|
-
network
|
|
29
|
+
network,
|
|
29
30
|
key: toAddress
|
|
30
31
|
}
|
|
31
32
|
};
|
|
32
33
|
}
|
|
33
34
|
return {
|
|
34
35
|
AccountId32: {
|
|
35
|
-
network
|
|
36
|
+
network,
|
|
36
37
|
id: decodeAddress(toAddress)
|
|
37
38
|
}
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
|
-
export function getBeneficiary(
|
|
41
|
-
const receiverLocation = getReceiverLocation(
|
|
41
|
+
export function getBeneficiary(destinationChainInfo, recipientAddress, version = 'V1') {
|
|
42
|
+
const receiverLocation = getReceiverLocation(destinationChainInfo, recipientAddress, version);
|
|
42
43
|
return {
|
|
43
44
|
[version]: {
|
|
44
45
|
parents: 0,
|
|
@@ -50,8 +51,68 @@ export function getBeneficiary(originChainInfo, destinationChainInfo, recipientA
|
|
|
50
51
|
}
|
|
51
52
|
export function getDestWeight() {
|
|
52
53
|
return 'Unlimited';
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
}
|
|
55
|
+
export function getTokenLocation(tokenInfo, sendingValue, version = 'V1') {
|
|
56
|
+
if (!_isNativeToken(tokenInfo)) {
|
|
57
|
+
const multilocation = _getXcmAssetMultilocation(tokenInfo);
|
|
58
|
+
return {
|
|
59
|
+
[version]: [{
|
|
60
|
+
id: multilocation,
|
|
61
|
+
fun: {
|
|
62
|
+
Fungible: sendingValue
|
|
63
|
+
}
|
|
64
|
+
}]
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
[version]: [{
|
|
69
|
+
id: {
|
|
70
|
+
Concrete: {
|
|
71
|
+
parents: 0,
|
|
72
|
+
interior: 'Here'
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
fun: {
|
|
76
|
+
Fungible: sendingValue
|
|
77
|
+
}
|
|
78
|
+
}]
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function getDestMultilocation(destinationChainInfo, recipient, version = 'V1') {
|
|
82
|
+
const receiverLocation = getReceiverLocation(destinationChainInfo, recipient, version);
|
|
83
|
+
if (_isSubstrateParaChain(destinationChainInfo)) {
|
|
84
|
+
const interior = {
|
|
85
|
+
X2: [{
|
|
86
|
+
Parachain: _getSubstrateParaId(destinationChainInfo)
|
|
87
|
+
}, receiverLocation]
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
[version]: {
|
|
91
|
+
parents: 1,
|
|
92
|
+
interior
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
[version]: {
|
|
98
|
+
parents: 1,
|
|
99
|
+
interior: {
|
|
100
|
+
X1: receiverLocation
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export function getDestinationChainLocation(originChainInfo, destinationChainInfo, version = 'V1') {
|
|
106
|
+
const parents = _isSubstrateRelayChain(originChainInfo) ? 0 : 1;
|
|
107
|
+
const interior = _isSubstrateParaChain(destinationChainInfo) ? {
|
|
108
|
+
X1: {
|
|
109
|
+
Parachain: _getSubstrateParaId(destinationChainInfo)
|
|
110
|
+
}
|
|
111
|
+
} : 'Here';
|
|
112
|
+
return {
|
|
113
|
+
[version]: {
|
|
114
|
+
parents,
|
|
115
|
+
interior
|
|
116
|
+
}
|
|
117
|
+
};
|
|
57
118
|
}
|
package/koni/api/xcm/xTokens.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// Copyright 2019-2022 @subwallet/extension-base
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
import { FOUR_INSTRUCTIONS_WEIGHT,
|
|
5
|
-
import {
|
|
6
|
-
import { _getSubstrateParaId, _getTokenOnChainInfo, _getXcmAssetId, _getXcmAssetMultilocation, _getXcmAssetType, _getXcmTransferType, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
|
|
4
|
+
import { FOUR_INSTRUCTIONS_WEIGHT, getDestMultilocation, getDestWeight } from '@subwallet/extension-base/koni/api/xcm/utils';
|
|
5
|
+
import { _getTokenOnChainAssetId, _getTokenOnChainInfo, _getXcmAssetId, _getXcmAssetMultilocation, _getXcmAssetType, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
|
|
7
6
|
function getCurrencyId(tokenInfo) {
|
|
8
7
|
if (['acala', 'karura'].includes(tokenInfo.originChain) && _isNativeToken(tokenInfo)) {
|
|
9
8
|
return _getXcmAssetMultilocation(tokenInfo);
|
|
@@ -16,38 +15,10 @@ function getCurrencyId(tokenInfo) {
|
|
|
16
15
|
} else if (['pioneer'].includes(tokenInfo.originChain)) {
|
|
17
16
|
return _getXcmAssetMultilocation(tokenInfo);
|
|
18
17
|
}
|
|
19
|
-
return _getTokenOnChainInfo(tokenInfo);
|
|
20
|
-
}
|
|
21
|
-
function getMultiLocationForXtokensPallet(originChainInfo, destinationChainInfo, toAddress) {
|
|
22
|
-
const xcmType = _getXcmTransferType(originChainInfo, destinationChainInfo);
|
|
23
|
-
const paraId = _getSubstrateParaId(destinationChainInfo);
|
|
24
|
-
const receiverLocation = getReceiverLocation(originChainInfo, destinationChainInfo, toAddress);
|
|
25
|
-
if (xcmType === _XCM_TYPE.PP) {
|
|
26
|
-
// parachain -> parachain
|
|
27
|
-
const interior = {
|
|
28
|
-
X2: [{
|
|
29
|
-
Parachain: paraId
|
|
30
|
-
}, receiverLocation]
|
|
31
|
-
};
|
|
32
|
-
return {
|
|
33
|
-
V1: {
|
|
34
|
-
parents: 1,
|
|
35
|
-
interior
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// parachain -> relaychain by default
|
|
41
|
-
return {
|
|
42
|
-
V1: {
|
|
43
|
-
parents: 1,
|
|
44
|
-
interior: {
|
|
45
|
-
X1: receiverLocation
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
};
|
|
18
|
+
return _getTokenOnChainInfo(tokenInfo) || _getTokenOnChainAssetId(tokenInfo);
|
|
49
19
|
}
|
|
50
20
|
export function getExtrinsicByXtokensPallet(tokenInfo, originChainInfo, destinationChainInfo, recipientAddress, value, api) {
|
|
51
|
-
const weightParam = ['pioneer'].includes(originChainInfo.slug) ? FOUR_INSTRUCTIONS_WEIGHT : getDestWeight();
|
|
52
|
-
|
|
21
|
+
const weightParam = ['pioneer', 'hydradx_main'].includes(originChainInfo.slug) ? FOUR_INSTRUCTIONS_WEIGHT : getDestWeight();
|
|
22
|
+
const destVersion = ['moonbeam', 'moonriver'].includes(originChainInfo.slug) ? 'V3' : undefined;
|
|
23
|
+
return api.tx.xTokens.transfer(getCurrencyId(tokenInfo), value, getDestMultilocation(destinationChainInfo, recipientAddress, destVersion), weightParam);
|
|
53
24
|
}
|
|
@@ -1,44 +1,14 @@
|
|
|
1
1
|
// Copyright 2019-2022 @subwallet/extension-base
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
import { getBeneficiary, getDestWeight } from '@subwallet/extension-base/koni/api/xcm/utils';
|
|
5
|
-
import { _getSubstrateParaId } from '@subwallet/extension-base/services/chain-service/utils';
|
|
6
|
-
function getDestinationChainLocation(destinationChainInfo, version = 'V1') {
|
|
7
|
-
return {
|
|
8
|
-
[version]: {
|
|
9
|
-
parents: 0,
|
|
10
|
-
interior: {
|
|
11
|
-
X1: {
|
|
12
|
-
Parachain: _getSubstrateParaId(destinationChainInfo)
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
function getTokenLocation(sendingValue, version = 'V2') {
|
|
19
|
-
return {
|
|
20
|
-
// always native token of relaychain
|
|
21
|
-
[version]: [{
|
|
22
|
-
id: {
|
|
23
|
-
Concrete: {
|
|
24
|
-
parents: 0,
|
|
25
|
-
interior: 'Here'
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
fun: {
|
|
29
|
-
Fungible: sendingValue
|
|
30
|
-
}
|
|
31
|
-
}]
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
4
|
+
import { getBeneficiary, getDestinationChainLocation, getDestWeight, getTokenLocation } from '@subwallet/extension-base/koni/api/xcm/utils';
|
|
35
5
|
// this pallet is only used by Relaychains
|
|
36
6
|
export function getExtrinsicByXcmPalletPallet(tokenInfo, originChainInfo, destinationChainInfo, recipientAddress, value, api) {
|
|
37
7
|
const weightParam = getDestWeight();
|
|
38
|
-
const xcmVer = ['kusama'].includes(originChainInfo.slug) ? '
|
|
39
|
-
const destination = getDestinationChainLocation(destinationChainInfo, xcmVer);
|
|
40
|
-
const beneficiary = getBeneficiary(
|
|
41
|
-
const tokenLocation = getTokenLocation(value, xcmVer);
|
|
8
|
+
const xcmVer = ['kusama'].includes(originChainInfo.slug) ? 'V3' : 'V1';
|
|
9
|
+
const destination = getDestinationChainLocation(originChainInfo, destinationChainInfo, xcmVer);
|
|
10
|
+
const beneficiary = getBeneficiary(destinationChainInfo, recipientAddress, xcmVer);
|
|
11
|
+
const tokenLocation = getTokenLocation(tokenInfo, value, xcmVer);
|
|
42
12
|
let method = 'limitedReserveTransferAssets';
|
|
43
13
|
if (['statemint', 'statemine'].includes(destinationChainInfo.slug)) {
|
|
44
14
|
method = 'limitedTeleportAssets';
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import Common from '@ethereumjs/common';
|
|
5
|
+
import { _AssetType } from '@subwallet/chain-list/types';
|
|
5
6
|
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
6
7
|
import { isJsonPayload, SEED_DEFAULT_LENGTH, SEED_LENGTHS } from '@subwallet/extension-base/background/handlers/Extension';
|
|
7
8
|
import { withErrorLog } from '@subwallet/extension-base/background/handlers/helpers';
|
|
8
9
|
import { createSubscription } from '@subwallet/extension-base/background/handlers/subscriptions';
|
|
9
|
-
import { AccountExternalErrorCode, BasicTxErrorType, ChainType, ExternalRequestPromiseStatus, ExtrinsicType, StakingType, TransferTxErrorType } from '@subwallet/extension-base/background/KoniTypes';
|
|
10
|
-
import {
|
|
10
|
+
import { AccountExternalErrorCode, BasicTxErrorType, BasicTxWarningCode, ChainType, ExternalRequestPromiseStatus, ExtrinsicType, StakingType, TransferTxErrorType } from '@subwallet/extension-base/background/KoniTypes';
|
|
11
|
+
import { TransactionWarning } from '@subwallet/extension-base/background/warnings/TransactionWarning';
|
|
12
|
+
import { ALL_ACCOUNT_KEY, ALL_GENESIS_HASH, XCM_MIN_AMOUNT_RATIO } from '@subwallet/extension-base/constants';
|
|
11
13
|
import { ALLOWED_PATH } from '@subwallet/extension-base/defaults';
|
|
12
14
|
import { parseSubstrateTransaction } from '@subwallet/extension-base/koni/api/dotsama/parseTransaction';
|
|
13
15
|
import { checkReferenceCount, checkSupportTransfer, createTransferExtrinsic } from '@subwallet/extension-base/koni/api/dotsama/transfer';
|
|
@@ -25,6 +27,7 @@ import { reformatAddress } from '@subwallet/extension-base/utils';
|
|
|
25
27
|
import { convertSubjectInfoToAddresses } from '@subwallet/extension-base/utils/address';
|
|
26
28
|
import { createTransactionFromRLP, signatureToHex } from '@subwallet/extension-base/utils/eth';
|
|
27
29
|
import { parseContractInput, parseEvmRlp } from '@subwallet/extension-base/utils/eth/parseTransaction';
|
|
30
|
+
import { balanceFormatter, formatNumber } from '@subwallet/extension-base/utils/number';
|
|
28
31
|
import { createPair } from '@subwallet/keyring';
|
|
29
32
|
import { keyring } from '@subwallet/ui-keyring';
|
|
30
33
|
import BigN from 'bignumber.js';
|
|
@@ -1398,31 +1401,58 @@ export default class KoniExtension {
|
|
|
1398
1401
|
|
|
1399
1402
|
// Get native token amount
|
|
1400
1403
|
const freeBalance = await this.#koniState.balanceService.getTokenFreeBalance(from, networkKey, tokenSlug);
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1404
|
+
try {
|
|
1405
|
+
if (isEthereumAddress(from) && isEthereumAddress(to) && _isTokenTransferredByEvm(tokenInfo)) {
|
|
1406
|
+
// TODO: review this
|
|
1407
|
+
chainType = ChainType.EVM;
|
|
1408
|
+
const txVal = transferAll ? freeBalance.value : value || '0';
|
|
1409
|
+
|
|
1410
|
+
// Estimate with EVM API
|
|
1411
|
+
if (_isTokenEvmSmartContract(tokenInfo) || _isLocalToken(tokenInfo)) {
|
|
1412
|
+
[transaction, transferAmount.value] = await getERC20TransactionObject(_getContractAddressOfToken(tokenInfo), chainInfo, from, to, txVal, !!transferAll, evmApiMap);
|
|
1413
|
+
} else {
|
|
1414
|
+
[transaction, transferAmount.value] = await getEVMTransactionObject(chainInfo, to, txVal, !!transferAll, evmApiMap);
|
|
1415
|
+
}
|
|
1409
1416
|
} else {
|
|
1410
|
-
|
|
1417
|
+
const substrateApi = this.#koniState.getSubstrateApi(networkKey);
|
|
1418
|
+
[transaction, transferAmount.value] = await createTransferExtrinsic({
|
|
1419
|
+
transferAll: !!transferAll,
|
|
1420
|
+
value: value || '0',
|
|
1421
|
+
from: from,
|
|
1422
|
+
networkKey,
|
|
1423
|
+
tokenInfo,
|
|
1424
|
+
to: to,
|
|
1425
|
+
substrateApi
|
|
1426
|
+
});
|
|
1411
1427
|
}
|
|
1412
|
-
}
|
|
1413
|
-
const
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
networkKey,
|
|
1419
|
-
tokenInfo,
|
|
1420
|
-
to: to,
|
|
1421
|
-
substrateApi
|
|
1422
|
-
});
|
|
1428
|
+
} catch (e) {
|
|
1429
|
+
const error = e;
|
|
1430
|
+
if (error.message.includes('transfer amount exceeds balance')) {
|
|
1431
|
+
error.message = 'Not enough balance';
|
|
1432
|
+
}
|
|
1433
|
+
throw error;
|
|
1423
1434
|
}
|
|
1424
1435
|
const transferNativeAmount = isTransferNativeToken ? transferAmount.value : '0';
|
|
1425
1436
|
this.addContact(to);
|
|
1437
|
+
const additionalValidator = async inputTransaction => {
|
|
1438
|
+
const minAmount = tokenInfo.minAmount || '0';
|
|
1439
|
+
if (!isTransferNativeToken) {
|
|
1440
|
+
const {
|
|
1441
|
+
value: balance
|
|
1442
|
+
} = await this.#koniState.balanceService.getTokenFreeBalance(from, networkKey, tokenSlug);
|
|
1443
|
+
if (new BigN(balance).minus(transferAmount.value).lt(minAmount)) {
|
|
1444
|
+
inputTransaction.warnings.push(new TransactionWarning(BasicTxWarningCode.NOT_ENOUGH_EXISTENTIAL_DEPOSIT, ''));
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
const {
|
|
1448
|
+
value: receiverBalance
|
|
1449
|
+
} = await this.#koniState.balanceService.getTokenFreeBalance(to, networkKey, tokenSlug);
|
|
1450
|
+
if (new BigN(receiverBalance).plus(transferAmount.value).lt(minAmount)) {
|
|
1451
|
+
const atLeast = new BigN(minAmount).minus(receiverBalance).plus((tokenInfo.decimals || 0) === 0 ? 0 : 1);
|
|
1452
|
+
const atLeastStr = formatNumber(atLeast, tokenInfo.decimals || 0, balanceFormatter);
|
|
1453
|
+
inputTransaction.errors.push(new TransactionError(TransferTxErrorType.RECEIVER_NOT_ENOUGH_EXISTENTIAL_DEPOSIT, `You must transfer at least ${atLeastStr} ${tokenInfo.symbol} to keep the destination account alive`));
|
|
1454
|
+
}
|
|
1455
|
+
};
|
|
1426
1456
|
return this.#koniState.transactionService.handleTransaction({
|
|
1427
1457
|
errors,
|
|
1428
1458
|
warnings,
|
|
@@ -1434,8 +1464,9 @@ export default class KoniExtension {
|
|
|
1434
1464
|
data: inputData,
|
|
1435
1465
|
extrinsicType: isTransferNativeToken ? ExtrinsicType.TRANSFER_BALANCE : ExtrinsicType.TRANSFER_TOKEN,
|
|
1436
1466
|
ignoreWarnings: transferAll,
|
|
1437
|
-
isTransferAll: transferAll,
|
|
1438
|
-
edAsWarning: isTransferNativeToken
|
|
1467
|
+
isTransferAll: isTransferNativeToken ? transferAll : false,
|
|
1468
|
+
edAsWarning: isTransferNativeToken,
|
|
1469
|
+
additionalValidator: additionalValidator
|
|
1439
1470
|
});
|
|
1440
1471
|
}
|
|
1441
1472
|
validateCrossChainTransfer(destinationNetworkKey, sendingTokenSlug, sender, sendingValue) {
|
|
@@ -1463,6 +1494,8 @@ export default class KoniExtension {
|
|
|
1463
1494
|
if (errors.length > 0) {
|
|
1464
1495
|
return this.#koniState.transactionService.generateBeforeHandleResponseErrors(errors);
|
|
1465
1496
|
}
|
|
1497
|
+
let additionalValidator;
|
|
1498
|
+
let eventsHandler;
|
|
1466
1499
|
if (fromKeyPair && destinationTokenInfo) {
|
|
1467
1500
|
const substrateApi = this.#koniState.getSubstrateApi(originNetworkKey);
|
|
1468
1501
|
const chainInfoMap = this.#koniState.getChainInfoMap();
|
|
@@ -1474,6 +1507,40 @@ export default class KoniExtension {
|
|
|
1474
1507
|
chainInfoMap,
|
|
1475
1508
|
substrateApi
|
|
1476
1509
|
});
|
|
1510
|
+
additionalValidator = async inputTransaction => {
|
|
1511
|
+
const destMinAmount = destinationTokenInfo.minAmount || '0';
|
|
1512
|
+
const atLeast = new BigN(destMinAmount).multipliedBy(XCM_MIN_AMOUNT_RATIO);
|
|
1513
|
+
if (new BigN(value).lt(atLeast)) {
|
|
1514
|
+
const atLeastStr = formatNumber(atLeast, destinationTokenInfo.decimals || 0, balanceFormatter);
|
|
1515
|
+
inputTransaction.errors.push(new TransactionError(TransferTxErrorType.RECEIVER_NOT_ENOUGH_EXISTENTIAL_DEPOSIT, `You must transfer at least ${atLeastStr} ${originTokenInfo.symbol} to keep the destination account alive`));
|
|
1516
|
+
}
|
|
1517
|
+
const srcMinAmount = originTokenInfo.minAmount || '0';
|
|
1518
|
+
const isTransferNativeToken = originTokenInfo.assetType === _AssetType.NATIVE;
|
|
1519
|
+
if (!isTransferNativeToken) {
|
|
1520
|
+
const {
|
|
1521
|
+
value: balance
|
|
1522
|
+
} = await this.#koniState.balanceService.getTokenFreeBalance(from, originNetworkKey, originTokenInfo.slug);
|
|
1523
|
+
if (new BigN(balance).minus(value).lt(srcMinAmount)) {
|
|
1524
|
+
inputTransaction.warnings.push(new TransactionWarning(BasicTxWarningCode.NOT_ENOUGH_EXISTENTIAL_DEPOSIT, ''));
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
};
|
|
1528
|
+
eventsHandler = eventEmitter => {
|
|
1529
|
+
eventEmitter.on('send', () => {
|
|
1530
|
+
try {
|
|
1531
|
+
const dest = keyring.getPair(to);
|
|
1532
|
+
if (dest) {
|
|
1533
|
+
this.updateAssetSetting({
|
|
1534
|
+
autoEnableNativeToken: false,
|
|
1535
|
+
tokenSlug: destinationTokenInfo.slug,
|
|
1536
|
+
assetSetting: {
|
|
1537
|
+
visible: true
|
|
1538
|
+
}
|
|
1539
|
+
}).catch(console.error);
|
|
1540
|
+
}
|
|
1541
|
+
} catch (e) {}
|
|
1542
|
+
});
|
|
1543
|
+
};
|
|
1477
1544
|
}
|
|
1478
1545
|
this.addContact(to);
|
|
1479
1546
|
return await this.#koniState.transactionService.handleTransaction({
|
|
@@ -1485,8 +1552,11 @@ export default class KoniExtension {
|
|
|
1485
1552
|
extrinsicType: ExtrinsicType.TRANSFER_XCM,
|
|
1486
1553
|
chainType: ChainType.SUBSTRATE,
|
|
1487
1554
|
transferNativeAmount: _isNativeToken(originTokenInfo) ? value : '0',
|
|
1555
|
+
ignoreWarnings: inputData.transferAll,
|
|
1488
1556
|
isTransferAll: inputData.transferAll,
|
|
1489
|
-
errors
|
|
1557
|
+
errors,
|
|
1558
|
+
additionalValidator: additionalValidator,
|
|
1559
|
+
eventsHandler: eventsHandler
|
|
1490
1560
|
});
|
|
1491
1561
|
}
|
|
1492
1562
|
async evmNftSubmitTransaction(inputData) {
|
|
@@ -1524,8 +1594,11 @@ export default class KoniExtension {
|
|
|
1524
1594
|
disableChain(networkKey) {
|
|
1525
1595
|
return this.#koniState.disableChain(networkKey);
|
|
1526
1596
|
}
|
|
1527
|
-
async enableChain(
|
|
1528
|
-
|
|
1597
|
+
async enableChain({
|
|
1598
|
+
chainSlug,
|
|
1599
|
+
enableTokens
|
|
1600
|
+
}) {
|
|
1601
|
+
return await this.#koniState.enableChain(chainSlug, enableTokens);
|
|
1529
1602
|
}
|
|
1530
1603
|
async validateNetwork({
|
|
1531
1604
|
existedChainSlug,
|
|
@@ -1715,9 +1788,15 @@ export default class KoniExtension {
|
|
|
1715
1788
|
isSendingSelf
|
|
1716
1789
|
};
|
|
1717
1790
|
}
|
|
1718
|
-
async enableChains(
|
|
1791
|
+
async enableChains({
|
|
1792
|
+
chainSlugs,
|
|
1793
|
+
enableTokens
|
|
1794
|
+
}) {
|
|
1719
1795
|
try {
|
|
1720
|
-
await Promise.all(
|
|
1796
|
+
await Promise.all(chainSlugs.map(chainSlug => this.enableChain({
|
|
1797
|
+
chainSlug,
|
|
1798
|
+
enableTokens
|
|
1799
|
+
})));
|
|
1721
1800
|
} catch (e) {
|
|
1722
1801
|
return false;
|
|
1723
1802
|
}
|
|
@@ -2839,6 +2918,7 @@ export default class KoniExtension {
|
|
|
2839
2918
|
return Object.fromEntries(Object.entries(rs).map(([key, value]) => {
|
|
2840
2919
|
const {
|
|
2841
2920
|
additionalValidator,
|
|
2921
|
+
eventsHandler,
|
|
2842
2922
|
transaction,
|
|
2843
2923
|
...transactionResult
|
|
2844
2924
|
} = value;
|