Skip to content

Commit 5fafc9d

Browse files
authored
Merge pull request #4285 from Koniverse/koni/dev/issue-4282
[Issue-4282] Refactor Across bridge
2 parents 6fff6b2 + 9298abf commit 5fafc9d

File tree

7 files changed

+165
-113
lines changed

7 files changed

+165
-113
lines changed

packages/extension-base/src/koni/background/handlers/Extension.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { getERC20TransactionObject, getERC721Transaction, getEVMTransactionObjec
3535
import { createSubstrateExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/token';
3636
import { createTonTransaction } from '@subwallet/extension-base/services/balance-service/transfer/ton-transfer';
3737
import { createAcrossBridgeExtrinsic, createAvailBridgeExtrinsicFromAvail, createAvailBridgeTxFromEth, createPolygonBridgeExtrinsic, createSnowBridgeExtrinsic, CreateXcmExtrinsicProps, createXcmExtrinsicV2, dryRunXcmExtrinsicV2, FunctionCreateXcmExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
38-
import { _isAcrossChainBridge, getAcrossQuote } from '@subwallet/extension-base/services/balance-service/transfer/xcm/acrossBridge';
38+
import { _isAcrossChainBridge, AcrossQuote, getAcrossQuote } from '@subwallet/extension-base/services/balance-service/transfer/xcm/acrossBridge';
3939
import { getClaimTxOnAvail, getClaimTxOnEthereum, isAvailChainBridge } from '@subwallet/extension-base/services/balance-service/transfer/xcm/availBridge';
4040
import { _isPolygonChainBridge, getClaimPolygonBridge, isClaimedPolygonBridge } from '@subwallet/extension-base/services/balance-service/transfer/xcm/polygonBridge';
4141
import { _isPosChainBridge, getClaimPosBridge } from '@subwallet/extension-base/services/balance-service/transfer/xcm/posBridge';
@@ -1651,7 +1651,8 @@ export default class KoniExtension {
16511651
}
16521652

16531653
if (isAcrossBridgeTransfer) {
1654-
const metadata = await getAcrossQuote(params);
1654+
const data = await getAcrossQuote(params);
1655+
const metadata = data.metadata as AcrossQuote;
16551656

16561657
inputData.metadata = {
16571658
amountOut: metadata.outputAmount,

packages/extension-base/src/services/balance-service/helpers/process.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
import { COMMON_CHAIN_SLUGS } from '@subwallet/chain-list';
5-
import { _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types';
5+
import { _ChainAsset } from '@subwallet/chain-list/types';
66
import { _Address } from '@subwallet/extension-base/background/KoniTypes';
77
import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types';
88
import { CommonOptimalTransferPath, CommonStepType, DEFAULT_FIRST_STEP, MOCK_STEP_FEE } from '@subwallet/extension-base/types/service-base';
99

10-
import { _getEvmChainId } from '../../chain-service/utils';
11-
import { SpokePoolMapping } from '../transfer/xcm/acrossBridge';
12-
1310
export interface RequestOptimalTransferProcess {
1411
originChain: string,
1512
destChain?: string,
@@ -62,10 +59,7 @@ export async function getSnowbridgeTransferProcessFromEvm (address: string, evmA
6259
return Promise.resolve(result);
6360
}
6461

65-
export async function getAcrossbridgeTransferProcessFromEvm (originChainInfo: _ChainInfo): Promise<CommonOptimalTransferPath> {
66-
const chainId = _getEvmChainId(originChainInfo) as number;
67-
const SpokePoolAddress = SpokePoolMapping[chainId].SpokePool.address;
68-
62+
export async function getAcrossbridgeTransferProcessFromEvm (SpokePoolAddress: string): Promise<CommonOptimalTransferPath> {
6963
const result: CommonOptimalTransferPath = {
7064
totalFee: [MOCK_STEP_FEE],
7165
steps: [DEFAULT_FIRST_STEP]

packages/extension-base/src/services/balance-service/index.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import { BehaviorSubject } from 'rxjs';
2323

2424
import { noop } from '@polkadot/util';
2525

26-
import { _isAcrossChainBridge } from './transfer/xcm/acrossBridge';
26+
import { CreateXcmExtrinsicProps } from './transfer/xcm';
27+
import { _isAcrossChainBridge, getAcrossQuote } from './transfer/xcm/acrossBridge';
2728
import { BalanceMapImpl } from './BalanceMapImpl';
2829
import { subscribeBalance } from './helpers';
2930

@@ -647,7 +648,31 @@ export class BalanceService implements StoppableServiceInterface {
647648
const tokenInfo = this.state.chainService.getAssetBySlug(params.tokenSlug);
648649

649650
if (!_isNativeToken(tokenInfo)) {
650-
return getAcrossbridgeTransferProcessFromEvm(originChainInfo);
651+
const chainInfoMap = this.state.getChainInfoMap();
652+
const originTokenInfo = this.state.getAssetBySlug(params.tokenSlug);
653+
const destinationTokenInfo = this.state.getXcmEqualAssetByChain(params.destChain, params.tokenSlug);
654+
655+
if (!destinationTokenInfo) {
656+
throw new Error('Destination token info not found');
657+
}
658+
659+
const inputData = {
660+
destinationTokenInfo,
661+
originTokenInfo,
662+
sendingValue: params.amount,
663+
sender: params.address,
664+
recipient: params.address,
665+
destinationChain: chainInfoMap[destinationTokenInfo.originChain],
666+
originChain: chainInfoMap[originTokenInfo.originChain]
667+
} as CreateXcmExtrinsicProps;
668+
669+
const data = await getAcrossQuote(inputData);
670+
671+
if (!data) {
672+
throw new Error('Failed to fetch Across Bridge Data. Please try again later');
673+
}
674+
675+
return getAcrossbridgeTransferProcessFromEvm(data.to);
651676
}
652677
}
653678

packages/extension-base/src/services/balance-service/transfer/xcm/acrossBridge/index.ts

Lines changed: 100 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -26,111 +26,32 @@ export function _isAcrossTestnetBridge (srcChain: string): boolean {
2626
return srcChain === 'base_sepolia' || srcChain === 'arbitrum_sepolia' || srcChain === COMMON_CHAIN_SLUGS.ETHEREUM_SEPOLIA;
2727
}
2828

29-
export const SpokePoolMapping: Record<number, { SpokePool: { address: string; blockNumber: number } }> = {
30-
1: {
31-
SpokePool: { address: '0x5c7BCd6E7De5423a257D81B442095A1a6ced35C5', blockNumber: 17117454 }
32-
},
33-
10: {
34-
SpokePool: { address: '0x6f26Bf09B1C792e3228e5467807a900A503c0281', blockNumber: 93903076 }
35-
},
36-
11155111: {
37-
SpokePool: { address: '0x5ef6C01E11889d86803e0B23e3cB3F9E9d97B662', blockNumber: 5288470 }
38-
},
39-
11155420: {
40-
SpokePool: { address: '0x4e8E101924eDE233C13e2D8622DC8aED2872d505', blockNumber: 7762656 }
41-
},
42-
1135: {
43-
SpokePool: { address: '0x9552a0a6624A23B848060AE5901659CDDa1f83f8', blockNumber: 2602337 }
44-
},
45-
130: {
46-
SpokePool: { address: '0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64', blockNumber: 7915488 }
47-
},
48-
137: {
49-
SpokePool: { address: '0x9295ee1d8C5b022Be115A2AD3c30C72E34e7F096', blockNumber: 41908657 }
50-
},
51-
168587773: {
52-
SpokePool: { address: '0x5545092553Cf5Bf786e87a87192E902D50D8f022', blockNumber: 7634204 }
53-
},
54-
1868: {
55-
SpokePool: { address: '0x3baD7AD0728f9917d1Bf08af5782dCbD516cDd96', blockNumber: 1709997 }
56-
},
57-
288: {
58-
SpokePool: { address: '0xBbc6009fEfFc27ce705322832Cb2068F8C1e0A58', blockNumber: 619993 }
59-
},
60-
324: {
61-
SpokePool: { address: '0xE0B015E54d54fc84a6cB9B666099c46adE9335FF', blockNumber: 10352565 }
62-
},
63-
34443: {
64-
SpokePool: { address: '0x3baD7AD0728f9917d1Bf08af5782dCbD516cDd96', blockNumber: 8043187 }
65-
},
66-
37111: {
67-
SpokePool: { address: '0x6A0a7f39530923911832Dd60667CE5da5449967B', blockNumber: 156275 }
68-
},
69-
41455: {
70-
SpokePool: { address: '0x13fDac9F9b4777705db45291bbFF3c972c6d1d97', blockNumber: 4240318 }
71-
},
72-
4202: {
73-
SpokePool: { address: '0xeF684C38F94F48775959ECf2012D7E864ffb9dd4', blockNumber: 7267988 }
74-
},
75-
42161: {
76-
SpokePool: { address: '0xe35e9842fceaCA96570B734083f4a58e8F7C5f2A', blockNumber: 83868041 }
77-
},
78-
421614: {
79-
SpokePool: { address: '0x7E63A5f1a8F0B4d0934B2f2327DAED3F6bb2ee75', blockNumber: 12411026 }
80-
},
81-
480: {
82-
SpokePool: { address: '0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64', blockNumber: 4524742 }
83-
},
84-
534352: {
85-
SpokePool: { address: '0x3baD7AD0728f9917d1Bf08af5782dCbD516cDd96', blockNumber: 7489705 }
86-
},
87-
57073: {
88-
SpokePool: { address: '0xeF684C38F94F48775959ECf2012D7E864ffb9dd4', blockNumber: 1139240 }
89-
},
90-
59144: {
91-
SpokePool: { address: '0x7E63A5f1a8F0B4d0934B2f2327DAED3F6bb2ee75', blockNumber: 2721169 }
92-
},
93-
690: {
94-
SpokePool: { address: '0x13fDac9F9b4777705db45291bbFF3c972c6d1d97', blockNumber: 5512122 }
95-
},
96-
7777777: {
97-
SpokePool: { address: '0x13fDac9F9b4777705db45291bbFF3c972c6d1d97', blockNumber: 18382867 }
98-
},
99-
80002: {
100-
SpokePool: { address: '0xd08baaE74D6d2eAb1F3320B2E1a53eeb391ce8e5', blockNumber: 7529960 }
101-
},
102-
81457: {
103-
SpokePool: { address: '0x2D509190Ed0172ba588407D4c2df918F955Cc6E1', blockNumber: 5574280 }
104-
},
105-
8453: {
106-
SpokePool: { address: '0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64', blockNumber: 2164878 }
107-
},
108-
84532: {
109-
SpokePool: { address: '0x82B564983aE7274c86695917BBf8C99ECb6F0F8F', blockNumber: 6082004 }
110-
},
111-
919: {
112-
SpokePool: { address: '0xbd886FC0725Cc459b55BbFEb3E4278610331f83b', blockNumber: 13999465 }
113-
}
114-
};
115-
11629
export const AcrossErrorMsg = {
11730
AMOUNT_TOO_LOW: 'amount too low',
11831
AMOUNT_TOO_HIGH: 'amount too high'
11932
};
12033

121-
interface AcrossQuote {
34+
export interface AcrossQuote {
12235
outputAmount: string;
12336
rate: string;
12437
}
12538

39+
interface XcmApiResponse {
40+
sender: string;
41+
to: string;
42+
transferEncodedCall: string;
43+
value: string;
44+
metadata?: any;
45+
}
46+
12647
// Calculate fee for across bridge transfer
12748
export const getAcrossQuote = async ({ destinationChain,
12849
destinationTokenInfo,
12950
originChain,
13051
originTokenInfo,
13152
recipient,
13253
sender,
133-
sendingValue }: CreateXcmExtrinsicProps): Promise<AcrossQuote> => {
54+
sendingValue }: CreateXcmExtrinsicProps) => {
13455
const isAcrossBridgeXcm = _isAcrossBridgeXcm(originChain, destinationChain);
13556

13657
if (!isAcrossBridgeXcm) {
@@ -144,12 +65,99 @@ export const getAcrossQuote = async ({ destinationChain,
14465
try {
14566
const data = await subwalletApiSdk.xcmApi?.fetchXcmData(sender, originTokenInfo.slug, destinationTokenInfo.slug, recipient, sendingValue);
14667

147-
if (!data || !data.metadata) {
148-
throw new Error('Failed to get AcrossBridge quote');
68+
if (!data) {
69+
throw new Error('Failed to fetch Across Bridge Data. Please try again later');
14970
}
15071

151-
return data.metadata as AcrossQuote;
72+
return data as XcmApiResponse;
15273
} catch (error) {
15374
return Promise.reject(error);
15475
}
15576
};
77+
78+
// export const SpokePoolMapping: Record<number, { SpokePool: { address: string; blockNumber: number } }> = {
79+
// 1: {
80+
// SpokePool: { address: '0x5c7BCd6E7De5423a257D81B442095A1a6ced35C5', blockNumber: 17117454 }
81+
// },
82+
// 10: {
83+
// SpokePool: { address: '0x6f26Bf09B1C792e3228e5467807a900A503c0281', blockNumber: 93903076 }
84+
// },
85+
// 11155111: {
86+
// SpokePool: { address: '0x5ef6C01E11889d86803e0B23e3cB3F9E9d97B662', blockNumber: 5288470 }
87+
// },
88+
// 11155420: {
89+
// SpokePool: { address: '0x4e8E101924eDE233C13e2D8622DC8aED2872d505', blockNumber: 7762656 }
90+
// },
91+
// 1135: {
92+
// SpokePool: { address: '0x9552a0a6624A23B848060AE5901659CDDa1f83f8', blockNumber: 2602337 }
93+
// },
94+
// 130: {
95+
// SpokePool: { address: '0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64', blockNumber: 7915488 }
96+
// },
97+
// 137: {
98+
// SpokePool: { address: '0x9295ee1d8C5b022Be115A2AD3c30C72E34e7F096', blockNumber: 41908657 }
99+
// },
100+
// 168587773: {
101+
// SpokePool: { address: '0x5545092553Cf5Bf786e87a87192E902D50D8f022', blockNumber: 7634204 }
102+
// },
103+
// 1868: {
104+
// SpokePool: { address: '0x3baD7AD0728f9917d1Bf08af5782dCbD516cDd96', blockNumber: 1709997 }
105+
// },
106+
// 288: {
107+
// SpokePool: { address: '0xBbc6009fEfFc27ce705322832Cb2068F8C1e0A58', blockNumber: 619993 }
108+
// },
109+
// 324: {
110+
// SpokePool: { address: '0xE0B015E54d54fc84a6cB9B666099c46adE9335FF', blockNumber: 10352565 }
111+
// },
112+
// 34443: {
113+
// SpokePool: { address: '0x3baD7AD0728f9917d1Bf08af5782dCbD516cDd96', blockNumber: 8043187 }
114+
// },
115+
// 37111: {
116+
// SpokePool: { address: '0x6A0a7f39530923911832Dd60667CE5da5449967B', blockNumber: 156275 }
117+
// },
118+
// 41455: {
119+
// SpokePool: { address: '0x13fDac9F9b4777705db45291bbFF3c972c6d1d97', blockNumber: 4240318 }
120+
// },
121+
// 4202: {
122+
// SpokePool: { address: '0xeF684C38F94F48775959ECf2012D7E864ffb9dd4', blockNumber: 7267988 }
123+
// },
124+
// 42161: {
125+
// SpokePool: { address: '0xe35e9842fceaCA96570B734083f4a58e8F7C5f2A', blockNumber: 83868041 }
126+
// },
127+
// 421614: {
128+
// SpokePool: { address: '0x7E63A5f1a8F0B4d0934B2f2327DAED3F6bb2ee75', blockNumber: 12411026 }
129+
// },
130+
// 480: {
131+
// SpokePool: { address: '0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64', blockNumber: 4524742 }
132+
// },
133+
// 534352: {
134+
// SpokePool: { address: '0x3baD7AD0728f9917d1Bf08af5782dCbD516cDd96', blockNumber: 7489705 }
135+
// },
136+
// 57073: {
137+
// SpokePool: { address: '0xeF684C38F94F48775959ECf2012D7E864ffb9dd4', blockNumber: 1139240 }
138+
// },
139+
// 59144: {
140+
// SpokePool: { address: '0x7E63A5f1a8F0B4d0934B2f2327DAED3F6bb2ee75', blockNumber: 2721169 }
141+
// },
142+
// 690: {
143+
// SpokePool: { address: '0x13fDac9F9b4777705db45291bbFF3c972c6d1d97', blockNumber: 5512122 }
144+
// },
145+
// 7777777: {
146+
// SpokePool: { address: '0x13fDac9F9b4777705db45291bbFF3c972c6d1d97', blockNumber: 18382867 }
147+
// },
148+
// 80002: {
149+
// SpokePool: { address: '0xd08baaE74D6d2eAb1F3320B2E1a53eeb391ce8e5', blockNumber: 7529960 }
150+
// },
151+
// 81457: {
152+
// SpokePool: { address: '0x2D509190Ed0172ba588407D4c2df918F955Cc6E1', blockNumber: 5574280 }
153+
// },
154+
// 8453: {
155+
// SpokePool: { address: '0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64', blockNumber: 2164878 }
156+
// },
157+
// 84532: {
158+
// SpokePool: { address: '0x82B564983aE7274c86695917BBf8C99ECb6F0F8F', blockNumber: 6082004 }
159+
// },
160+
// 919: {
161+
// SpokePool: { address: '0xbd886FC0725Cc459b55BbFEb3E4278610331f83b', blockNumber: 13999465 }
162+
// }
163+
// };

packages/extension-base/src/services/balance-service/transfer/xcm/index.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,15 @@ export const createAcrossBridgeExtrinsic = async ({ destinationChain,
233233
const _feeCustom = feeCustom as EvmEIP1559FeeOption;
234234
const feeCombine = combineEthFee(feeInfo as EvmFeeInfo, feeOption, _feeCustom);
235235

236-
// todo: validate data before sending
236+
if (!data) {
237+
throw new Error('Failed to fetch Across Bridge Data. Please try again later');
238+
}
239+
237240
const transactionConfig: TransactionConfig = {
238-
from: data?.sender,
239-
to: data?.to,
240-
value: data?.value,
241-
data: data?.transferEncodedCall,
241+
from: data.sender,
242+
to: data.to,
243+
value: data.value,
244+
data: data.transferEncodedCall,
242245
...feeCombine
243246
};
244247

packages/extension-base/src/services/swap-service/handler/uniswap-handler.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { TransactionError } from '@subwallet/extension-base/background/errors/Tr
55
import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
66
import { validateTypedSignMessageDataV3V4 } from '@subwallet/extension-base/core/logic-validation';
77
import { estimateTxFee, getERC20Allowance, getERC20SpendingApprovalTx } from '@subwallet/extension-base/koni/api/contract-handler/evm/web3';
8-
import { createAcrossBridgeExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
9-
import { SpokePoolMapping } from '@subwallet/extension-base/services/balance-service/transfer/xcm/acrossBridge';
8+
import { createAcrossBridgeExtrinsic, CreateXcmExtrinsicProps } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
9+
import { getAcrossQuote } from '@subwallet/extension-base/services/balance-service/transfer/xcm/acrossBridge';
1010
import TransactionService from '@subwallet/extension-base/services/transaction-service';
1111
import { ApproveStepMetadata, BaseStepDetail, BaseSwapStepMetadata, BasicTxErrorType, CommonOptimalSwapPath, CommonStepFeeInfo, CommonStepType, DynamicSwapType, EvmFeeInfo, FeeOptionKey, GenSwapStepFuncV2, HandleYieldStepData, OptimalSwapPathParamsV2, PermitSwapData, SwapBaseTxData, SwapFeeType, SwapProviderId, SwapStepType, SwapSubmitParams, SwapSubmitStepData, TokenSpendingApprovalParams, ValidateSwapProcessParams } from '@subwallet/extension-base/types';
1212
import { _reformatAddressWithChain } from '@subwallet/extension-base/utils';
@@ -221,6 +221,7 @@ export class UniswapHandler implements SwapBaseInterface {
221221
return Promise.resolve(undefined);
222222
}
223223

224+
console.log('params', params);
224225
const sendingAmount = quote.toAmount;
225226
const senderAddress = params.request.address;
226227
const fromTokenInfo = this.chainService.getAssetBySlug(quote.pair.to);
@@ -229,6 +230,9 @@ export class UniswapHandler implements SwapBaseInterface {
229230
const evmApi = this.chainService.getEvmApi(fromChainInfo.slug);
230231
const tokenContract = _getContractAddressOfToken(fromTokenInfo);
231232

233+
const toTokenInfo = this.chainService.getAssetBySlug(params.request.pair.to);
234+
const toChainInfo = this.chainService.getChainInfoByKey(_getAssetOriginChain(toTokenInfo));
235+
232236
if (_isNativeToken(fromTokenInfo)) {
233237
return Promise.resolve(undefined);
234238
}
@@ -237,7 +241,21 @@ export class UniswapHandler implements SwapBaseInterface {
237241
throw Error('Error getting Evm chain Id');
238242
}
239243

240-
const spokePoolAddress = SpokePoolMapping[fromChainId].SpokePool.address;
244+
const inputData = {
245+
destinationTokenInfo: toTokenInfo,
246+
originTokenInfo: fromTokenInfo,
247+
sendingValue: sendingAmount,
248+
sender: senderAddress,
249+
recipient: senderAddress,
250+
destinationChain: toChainInfo,
251+
originChain: fromChainInfo
252+
} as CreateXcmExtrinsicProps;
253+
254+
const acrossQuote = await getAcrossQuote(
255+
inputData
256+
);
257+
258+
const spokePoolAddress = acrossQuote.to;
241259

242260
const allowance = await getERC20Allowance(spokePoolAddress, senderAddress, tokenContract, evmApi);
243261

packages/subwallet-api-sdk/src/modules/xcmApi.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ export class XcmApi {
5555

5656
return response.data;
5757
} catch (error) {
58-
console.error(error);
58+
if (error instanceof SyntaxError) {
59+
throw new Error('Unable to perform this transaction at the moment. Try again later');
60+
}
61+
5962
throw new Error((error as Error)?.message || 'Unable to perform this transaction at the moment. Try again later');
6063
}
6164
}

0 commit comments

Comments
 (0)