@pioneer-platform/pioneer-sdk 0.0.82 → 4.13.30
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/dist/index.cjs +5358 -0
- package/dist/index.es.js +5537 -0
- package/dist/index.js +5537 -0
- package/package.json +55 -37
- package/src/TransactionManager.ts +333 -0
- package/src/charts/cosmos-staking.ts +171 -0
- package/src/charts/evm.ts +199 -0
- package/src/charts/index.ts +46 -0
- package/src/charts/maya.ts +110 -0
- package/src/charts/types.ts +77 -0
- package/src/charts/utils.ts +24 -0
- package/src/fees/index.ts +620 -0
- package/src/getPubkey.ts +151 -0
- package/src/index.ts +2250 -0
- package/src/kkapi-batch-client.ts +191 -0
- package/src/offline-client.ts +287 -0
- package/src/supportedCaips.ts +36 -0
- package/src/txbuilder/createUnsignedEvmTx.ts +532 -0
- package/src/txbuilder/createUnsignedRippleTx.ts +122 -0
- package/src/txbuilder/createUnsignedStakingTx.ts +188 -0
- package/src/txbuilder/createUnsignedTendermintTx.ts +249 -0
- package/src/txbuilder/createUnsignedUxtoTx.ts +450 -0
- package/src/txbuilder/templates/cosmos-staking.ts +157 -0
- package/src/txbuilder/templates/cosmos.ts +30 -0
- package/src/txbuilder/templates/mayachain.ts +60 -0
- package/src/txbuilder/templates/osmosis.ts +30 -0
- package/src/txbuilder/templates/thorchain.ts +60 -0
- package/src/utils/build-dashboard.ts +181 -0
- package/src/utils/format-time.ts +12 -0
- package/src/utils/kkapi-detection.ts +64 -0
- package/src/utils/pubkey-helpers.ts +75 -0
- package/lib/index.d.ts +0 -66
- package/lib/index.js +0 -493
- package/tsconfig.json +0 -13
@@ -0,0 +1,199 @@
|
|
1
|
+
import { ChartBalance, ChartParams, PortfolioBalance, PortfolioToken } from './types';
|
2
|
+
import { hydrateAssetData, checkDuplicateBalance, createBalanceIdentifier } from './utils';
|
3
|
+
|
4
|
+
const tag = '| charts-evm |';
|
5
|
+
|
6
|
+
export async function getEvmCharts(params: ChartParams): Promise<ChartBalance[]> {
|
7
|
+
const { blockchains, pioneer, pubkeys, context } = params;
|
8
|
+
const balances: ChartBalance[] = [];
|
9
|
+
|
10
|
+
// Find the primary address for portfolio lookup
|
11
|
+
// ONLY use EVM addresses since the portfolio endpoint uses Zapper which only supports Ethereum
|
12
|
+
const evmPubkey = pubkeys.find(
|
13
|
+
(e: any) => e.networks && Array.isArray(e.networks) && e.networks.includes('eip155:*'),
|
14
|
+
);
|
15
|
+
const primaryAddress = evmPubkey?.address || evmPubkey?.master;
|
16
|
+
|
17
|
+
console.log(tag, 'Total pubkeys available:', pubkeys.length);
|
18
|
+
console.log(tag, 'Blockchains to process:', blockchains);
|
19
|
+
|
20
|
+
// Only call portfolio endpoint if we have an EVM address (Zapper requirement)
|
21
|
+
if (!primaryAddress) {
|
22
|
+
console.log(
|
23
|
+
tag,
|
24
|
+
'No EVM address found, skipping portfolio lookup (Zapper only supports Ethereum)',
|
25
|
+
);
|
26
|
+
return balances;
|
27
|
+
}
|
28
|
+
|
29
|
+
console.log(tag, 'Using EVM address for portfolio:', primaryAddress);
|
30
|
+
|
31
|
+
try {
|
32
|
+
let portfolio = await pioneer.GetPortfolio({ address: primaryAddress });
|
33
|
+
portfolio = portfolio.data;
|
34
|
+
|
35
|
+
if (!portfolio || !portfolio.balances) {
|
36
|
+
console.error(tag, 'No portfolio.balances found:', portfolio);
|
37
|
+
return balances;
|
38
|
+
}
|
39
|
+
|
40
|
+
// Process main balances
|
41
|
+
for (const balance of portfolio.balances) {
|
42
|
+
const processedBalance = processPortfolioBalance(balance, primaryAddress, context, blockchains);
|
43
|
+
if (processedBalance && !checkDuplicateBalance(balances, processedBalance.caip, processedBalance.pubkey)) {
|
44
|
+
balances.push(processedBalance);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
// Process tokens from portfolio (if they exist)
|
49
|
+
if (portfolio.tokens && portfolio.tokens.length > 0) {
|
50
|
+
console.log(tag, 'Processing portfolio.tokens:', portfolio.tokens.length);
|
51
|
+
|
52
|
+
for (const token of portfolio.tokens) {
|
53
|
+
const processedToken = processPortfolioToken(token, primaryAddress, context, blockchains);
|
54
|
+
if (processedToken && !checkDuplicateBalance(balances, processedToken.caip, processedToken.pubkey)) {
|
55
|
+
balances.push(processedToken);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
} catch (e) {
|
60
|
+
console.error(tag, 'Error fetching portfolio:', e);
|
61
|
+
}
|
62
|
+
|
63
|
+
return balances;
|
64
|
+
}
|
65
|
+
|
66
|
+
function processPortfolioBalance(
|
67
|
+
balance: PortfolioBalance,
|
68
|
+
primaryAddress: string,
|
69
|
+
context: string,
|
70
|
+
blockchains: string[]
|
71
|
+
): ChartBalance | null {
|
72
|
+
if (!balance.caip) {
|
73
|
+
console.error(tag, 'No caip found for:', balance);
|
74
|
+
return null;
|
75
|
+
}
|
76
|
+
|
77
|
+
// Always derive networkId from CAIP
|
78
|
+
const networkId = balance.caip.split('/')[0];
|
79
|
+
|
80
|
+
// Skip if not in requested blockchains
|
81
|
+
if (!blockchains.includes(networkId)) {
|
82
|
+
return null;
|
83
|
+
}
|
84
|
+
|
85
|
+
// Hydrate with assetData
|
86
|
+
const assetInfo = hydrateAssetData(balance.caip);
|
87
|
+
|
88
|
+
// CRITICAL FIX: Use the original balance.pubkey from API if it exists,
|
89
|
+
// otherwise fall back to primaryAddress. This ensures identifier consistency
|
90
|
+
// with regular balance fetching which uses the API's balance.pubkey value.
|
91
|
+
const balancePubkey = balance.pubkey || primaryAddress;
|
92
|
+
|
93
|
+
// Determine if this is a token balance
|
94
|
+
const balanceType = assetInfo?.type || balance.type || 'native';
|
95
|
+
const isToken = balanceType !== 'native' && balance.caip.includes('/erc20:');
|
96
|
+
|
97
|
+
// Calculate price from valueUsd and balance if not provided
|
98
|
+
let calculatedPrice = balance.priceUsd || balance.price || 0;
|
99
|
+
if ((!calculatedPrice || calculatedPrice === 0) && balance.valueUsd && balance.balance) {
|
100
|
+
const balanceNum = parseFloat(balance.balance.toString());
|
101
|
+
const valueNum = parseFloat(balance.valueUsd.toString());
|
102
|
+
if (balanceNum > 0 && valueNum > 0) {
|
103
|
+
calculatedPrice = valueNum / balanceNum;
|
104
|
+
console.log(tag, `Calculated price from value/balance: ${calculatedPrice} for ${balance.caip}`);
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
const chartBalance: ChartBalance = {
|
109
|
+
context,
|
110
|
+
chart: 'pioneer',
|
111
|
+
contextType: 'keepkey',
|
112
|
+
name: assetInfo?.name || balance.name || 'Unknown',
|
113
|
+
caip: balance.caip,
|
114
|
+
icon: assetInfo?.icon || balance.icon || '',
|
115
|
+
pubkey: balancePubkey,
|
116
|
+
ticker: assetInfo?.symbol || balance.symbol || 'UNK',
|
117
|
+
ref: `${context}${balance.caip}`,
|
118
|
+
identifier: createBalanceIdentifier(balance.caip, balancePubkey),
|
119
|
+
networkId,
|
120
|
+
chain: networkId,
|
121
|
+
symbol: assetInfo?.symbol || balance.symbol || 'UNK',
|
122
|
+
type: balanceType,
|
123
|
+
token: isToken,
|
124
|
+
decimal: assetInfo?.decimal || balance.decimal,
|
125
|
+
balance: balance.balance.toString(),
|
126
|
+
price: calculatedPrice,
|
127
|
+
priceUsd: calculatedPrice,
|
128
|
+
valueUsd: balance.valueUsd.toString(),
|
129
|
+
updated: new Date().getTime(),
|
130
|
+
};
|
131
|
+
|
132
|
+
// Handle display icon for multi-asset icons
|
133
|
+
if (balance.display) {
|
134
|
+
chartBalance.icon = ['multi', chartBalance.icon, balance.display.toString()].toString();
|
135
|
+
}
|
136
|
+
|
137
|
+
return chartBalance;
|
138
|
+
}
|
139
|
+
|
140
|
+
function processPortfolioToken(
|
141
|
+
token: PortfolioToken,
|
142
|
+
primaryAddress: string,
|
143
|
+
context: string,
|
144
|
+
blockchains: string[]
|
145
|
+
): ChartBalance | null {
|
146
|
+
if (!token.assetCaip || !token.networkId) {
|
147
|
+
return null;
|
148
|
+
}
|
149
|
+
|
150
|
+
// Extract the networkId from the assetCaip for special token formats
|
151
|
+
let extractedNetworkId = token.networkId;
|
152
|
+
|
153
|
+
// Special handling for tokens with special formats
|
154
|
+
if (token.assetCaip.includes('/denom:')) {
|
155
|
+
// Extract the network part before /denom:
|
156
|
+
const parts = token.assetCaip.split('/denom:');
|
157
|
+
if (parts.length > 0) {
|
158
|
+
extractedNetworkId = parts[0];
|
159
|
+
}
|
160
|
+
} else if (token.networkId && token.networkId.includes('/')) {
|
161
|
+
// For other tokens, split by / and take the first part
|
162
|
+
extractedNetworkId = token.networkId.split('/')[0];
|
163
|
+
}
|
164
|
+
|
165
|
+
// Skip if not in requested blockchains
|
166
|
+
if (!blockchains.includes(extractedNetworkId)) {
|
167
|
+
return null;
|
168
|
+
}
|
169
|
+
|
170
|
+
// Hydrate token with assetData
|
171
|
+
const tokenAssetInfo = hydrateAssetData(token.assetCaip);
|
172
|
+
|
173
|
+
// CRITICAL FIX: Use consistent pubkey for tokens too
|
174
|
+
const tokenPubkey = token.pubkey || primaryAddress;
|
175
|
+
|
176
|
+
const chartBalance: ChartBalance = {
|
177
|
+
context,
|
178
|
+
chart: 'pioneer',
|
179
|
+
contextType: context.split(':')[0],
|
180
|
+
name: tokenAssetInfo?.name || token.token?.coingeckoId || token.token?.name || 'Unknown',
|
181
|
+
caip: token.assetCaip,
|
182
|
+
icon: tokenAssetInfo?.icon || token.token?.icon || '',
|
183
|
+
pubkey: tokenPubkey,
|
184
|
+
ticker: tokenAssetInfo?.symbol || token.token?.symbol || 'UNK',
|
185
|
+
ref: `${context}${token.assetCaip}`,
|
186
|
+
identifier: createBalanceIdentifier(token.assetCaip, tokenPubkey),
|
187
|
+
networkId: extractedNetworkId,
|
188
|
+
symbol: tokenAssetInfo?.symbol || token.token?.symbol || 'UNK',
|
189
|
+
type: tokenAssetInfo?.type || 'token',
|
190
|
+
token: true, // Tokens from portfolio.tokens are always tokens
|
191
|
+
decimal: tokenAssetInfo?.decimal || token.token?.decimal,
|
192
|
+
balance: token.token?.balance?.toString() || '0',
|
193
|
+
priceUsd: token.token?.price || 0,
|
194
|
+
valueUsd: token.token?.balanceUSD || 0,
|
195
|
+
updated: new Date().getTime(),
|
196
|
+
};
|
197
|
+
|
198
|
+
return chartBalance;
|
199
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import { ChartBalance, ChartParams } from './types';
|
2
|
+
import { getEvmCharts } from './evm';
|
3
|
+
import { getMayaCharts } from './maya';
|
4
|
+
import { getCosmosStakingCharts } from './cosmos-staking';
|
5
|
+
|
6
|
+
const tag = '| getCharts |';
|
7
|
+
const TIMEOUT = 30000;
|
8
|
+
|
9
|
+
export const getCharts = async (
|
10
|
+
blockchains: any,
|
11
|
+
pioneer: any,
|
12
|
+
pubkeys: any,
|
13
|
+
context: string
|
14
|
+
): Promise<ChartBalance[]> => {
|
15
|
+
try {
|
16
|
+
const balances: ChartBalance[] = [];
|
17
|
+
console.log(tag, 'init');
|
18
|
+
|
19
|
+
const params: ChartParams = {
|
20
|
+
blockchains,
|
21
|
+
pioneer,
|
22
|
+
pubkeys,
|
23
|
+
context,
|
24
|
+
};
|
25
|
+
|
26
|
+
// Get EVM charts (includes portfolio and tokens)
|
27
|
+
const evmBalances = await getEvmCharts(params);
|
28
|
+
balances.push(...evmBalances);
|
29
|
+
|
30
|
+
// WORKAROUND: Check if MAYA tokens are missing and fetch them separately
|
31
|
+
const mayaBalances = await getMayaCharts(params, balances);
|
32
|
+
balances.push(...mayaBalances);
|
33
|
+
|
34
|
+
// Add Cosmos Staking Positions to charts
|
35
|
+
const stakingBalances = await getCosmosStakingCharts(params);
|
36
|
+
balances.push(...stakingBalances);
|
37
|
+
|
38
|
+
return balances;
|
39
|
+
} catch (error) {
|
40
|
+
console.error(tag, 'Error processing charts:', error);
|
41
|
+
throw error;
|
42
|
+
}
|
43
|
+
};
|
44
|
+
|
45
|
+
// Export types for external use
|
46
|
+
export * from './types';
|
@@ -0,0 +1,110 @@
|
|
1
|
+
import { ChartBalance, ChartParams } from './types';
|
2
|
+
import { hydrateAssetData, checkDuplicateBalance, createBalanceIdentifier } from './utils';
|
3
|
+
|
4
|
+
const tag = '| charts-maya |';
|
5
|
+
|
6
|
+
export async function getMayaCharts(
|
7
|
+
params: ChartParams,
|
8
|
+
existingBalances: ChartBalance[]
|
9
|
+
): Promise<ChartBalance[]> {
|
10
|
+
const { blockchains, pioneer, pubkeys, context } = params;
|
11
|
+
const balances: ChartBalance[] = [];
|
12
|
+
|
13
|
+
try {
|
14
|
+
// Check if we have a MAYA address
|
15
|
+
const mayaPubkey = pubkeys.find(
|
16
|
+
(p: any) =>
|
17
|
+
p.networks &&
|
18
|
+
Array.isArray(p.networks) &&
|
19
|
+
p.networks.includes('cosmos:mayachain-mainnet-v1'),
|
20
|
+
);
|
21
|
+
|
22
|
+
if (!mayaPubkey || !mayaPubkey.address) {
|
23
|
+
console.log(tag, 'No MAYA pubkey found, skipping MAYA token fetch');
|
24
|
+
return balances;
|
25
|
+
}
|
26
|
+
|
27
|
+
// Check if MAYA network is in the requested blockchains
|
28
|
+
if (!blockchains.includes('cosmos:mayachain-mainnet-v1')) {
|
29
|
+
console.log(tag, 'MAYA network not in blockchains list, skipping MAYA token fetch');
|
30
|
+
return balances;
|
31
|
+
}
|
32
|
+
|
33
|
+
// Check if MAYA token is already in existing balances
|
34
|
+
const hasMayaToken = existingBalances.some(
|
35
|
+
(b: any) => b.caip === 'cosmos:mayachain-mainnet-v1/denom:maya',
|
36
|
+
);
|
37
|
+
|
38
|
+
if (hasMayaToken) {
|
39
|
+
console.log(tag, 'MAYA token already exists in balances, skipping');
|
40
|
+
return balances;
|
41
|
+
}
|
42
|
+
|
43
|
+
console.log(tag, 'MAYA token not found in portfolio, fetching separately...');
|
44
|
+
console.log(tag, 'MAYA pubkey address:', mayaPubkey.address);
|
45
|
+
|
46
|
+
// Try to get MAYA token balance via a separate call
|
47
|
+
// This is a workaround for the portfolio API not returning MAYA tokens
|
48
|
+
const mayaBalanceResponse = await pioneer.GetPortfolioBalances([
|
49
|
+
{
|
50
|
+
caip: 'cosmos:mayachain-mainnet-v1/denom:maya',
|
51
|
+
pubkey: mayaPubkey.address,
|
52
|
+
},
|
53
|
+
]);
|
54
|
+
|
55
|
+
console.log(
|
56
|
+
tag,
|
57
|
+
'MAYA balance response:',
|
58
|
+
JSON.stringify(mayaBalanceResponse?.data, null, 2),
|
59
|
+
);
|
60
|
+
|
61
|
+
if (!mayaBalanceResponse?.data || mayaBalanceResponse.data.length === 0) {
|
62
|
+
console.log(tag, 'No MAYA token balance returned from GetPortfolioBalances API');
|
63
|
+
return balances;
|
64
|
+
}
|
65
|
+
|
66
|
+
console.log(tag, 'Found MAYA token balances:', mayaBalanceResponse.data.length);
|
67
|
+
|
68
|
+
for (const mayaBalance of mayaBalanceResponse.data) {
|
69
|
+
if (mayaBalance.caip !== 'cosmos:mayachain-mainnet-v1/denom:maya') {
|
70
|
+
console.log(tag, 'Unexpected balance in MAYA response:', mayaBalance);
|
71
|
+
continue;
|
72
|
+
}
|
73
|
+
|
74
|
+
// Hydrate MAYA token with assetData
|
75
|
+
const mayaAssetInfo = hydrateAssetData(mayaBalance.caip);
|
76
|
+
|
77
|
+
// CACAO is the native asset, MAYA is a token on the Maya chain
|
78
|
+
const isToken = mayaBalance.caip.includes('/denom:') && !mayaBalance.caip.endsWith('/denom:cacao');
|
79
|
+
|
80
|
+
const mayaTokenBalance: ChartBalance = {
|
81
|
+
context,
|
82
|
+
chart: 'pioneer',
|
83
|
+
contextType: context.split(':')[0],
|
84
|
+
name: mayaAssetInfo?.name || 'Maya Token',
|
85
|
+
caip: mayaBalance.caip,
|
86
|
+
icon: mayaAssetInfo?.icon || 'https://pioneers.dev/coins/maya.png',
|
87
|
+
pubkey: mayaPubkey.address,
|
88
|
+
ticker: mayaAssetInfo?.symbol || 'MAYA',
|
89
|
+
ref: `${context}${mayaBalance.caip}`,
|
90
|
+
identifier: createBalanceIdentifier(mayaBalance.caip, mayaPubkey.address),
|
91
|
+
networkId: 'cosmos:mayachain-mainnet-v1',
|
92
|
+
symbol: mayaAssetInfo?.symbol || 'MAYA',
|
93
|
+
type: mayaAssetInfo?.type || 'token',
|
94
|
+
token: isToken, // MAYA is a token, CACAO is the native asset
|
95
|
+
decimal: mayaAssetInfo?.decimal,
|
96
|
+
balance: mayaBalance.balance?.toString() || '0',
|
97
|
+
priceUsd: parseFloat(mayaBalance.priceUsd) || 0,
|
98
|
+
valueUsd: parseFloat(mayaBalance.valueUsd) || 0,
|
99
|
+
updated: new Date().getTime(),
|
100
|
+
};
|
101
|
+
|
102
|
+
console.log(tag, 'Adding MAYA token to balances:', mayaTokenBalance);
|
103
|
+
balances.push(mayaTokenBalance);
|
104
|
+
}
|
105
|
+
} catch (mayaError) {
|
106
|
+
console.error(tag, 'Error fetching MAYA token balance:', mayaError);
|
107
|
+
}
|
108
|
+
|
109
|
+
return balances;
|
110
|
+
}
|
@@ -0,0 +1,77 @@
|
|
1
|
+
export interface ChartBalance {
|
2
|
+
context: string;
|
3
|
+
chart: string;
|
4
|
+
contextType: string;
|
5
|
+
name: string;
|
6
|
+
caip: string;
|
7
|
+
icon: string;
|
8
|
+
pubkey: string;
|
9
|
+
ticker: string;
|
10
|
+
ref: string;
|
11
|
+
identifier: string;
|
12
|
+
networkId: string;
|
13
|
+
chain?: string;
|
14
|
+
symbol: string;
|
15
|
+
type: string;
|
16
|
+
token?: boolean; // Indicates if this is a token balance
|
17
|
+
decimal?: number;
|
18
|
+
balance: string;
|
19
|
+
priceUsd: number;
|
20
|
+
valueUsd: number | string;
|
21
|
+
updated: number;
|
22
|
+
display?: string;
|
23
|
+
status?: string;
|
24
|
+
validator?: string;
|
25
|
+
}
|
26
|
+
|
27
|
+
export interface ChartParams {
|
28
|
+
blockchains: string[];
|
29
|
+
pioneer: any;
|
30
|
+
pubkeys: any[];
|
31
|
+
context: string;
|
32
|
+
}
|
33
|
+
|
34
|
+
export interface PortfolioBalance {
|
35
|
+
caip: string;
|
36
|
+
networkId?: string;
|
37
|
+
pubkey?: string;
|
38
|
+
balance: string | number;
|
39
|
+
valueUsd: string | number;
|
40
|
+
name?: string;
|
41
|
+
symbol?: string;
|
42
|
+
icon?: string;
|
43
|
+
decimal?: number;
|
44
|
+
type?: string;
|
45
|
+
display?: string;
|
46
|
+
}
|
47
|
+
|
48
|
+
export interface PortfolioToken {
|
49
|
+
assetCaip: string;
|
50
|
+
networkId?: string;
|
51
|
+
pubkey?: string;
|
52
|
+
token?: {
|
53
|
+
name?: string;
|
54
|
+
symbol?: string;
|
55
|
+
icon?: string;
|
56
|
+
coingeckoId?: string;
|
57
|
+
decimal?: number;
|
58
|
+
balance?: string | number;
|
59
|
+
price?: number;
|
60
|
+
balanceUSD?: number;
|
61
|
+
};
|
62
|
+
}
|
63
|
+
|
64
|
+
export interface StakingPosition {
|
65
|
+
caip: string;
|
66
|
+
balance: number;
|
67
|
+
priceUsd?: number;
|
68
|
+
valueUsd?: number;
|
69
|
+
name?: string;
|
70
|
+
icon?: string;
|
71
|
+
ticker?: string;
|
72
|
+
symbol?: string;
|
73
|
+
type?: string;
|
74
|
+
status?: string;
|
75
|
+
validatorAddress?: string;
|
76
|
+
validator?: string;
|
77
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { assetData } from '@pioneer-platform/pioneer-discovery';
|
2
|
+
import { ChartBalance } from './types';
|
3
|
+
|
4
|
+
export function hydrateAssetData(caip: string): any {
|
5
|
+
return assetData[caip] || assetData[caip.toLowerCase()];
|
6
|
+
}
|
7
|
+
|
8
|
+
export function checkDuplicateBalance(
|
9
|
+
balances: ChartBalance[],
|
10
|
+
caip: string,
|
11
|
+
pubkey: string,
|
12
|
+
validator?: string
|
13
|
+
): boolean {
|
14
|
+
return balances.some(
|
15
|
+
(b) =>
|
16
|
+
b.caip === caip &&
|
17
|
+
b.pubkey === pubkey &&
|
18
|
+
(!validator || b.validator === validator)
|
19
|
+
);
|
20
|
+
}
|
21
|
+
|
22
|
+
export function createBalanceIdentifier(caip: string, pubkey: string): string {
|
23
|
+
return `${caip}:${pubkey}`;
|
24
|
+
}
|