dev
dart 145 lines 4.3 KB
Raw
1 import 'package:cw_core/amount/money.dart';
2 import 'package:cw_core/erc20_token.dart';
3 import 'package:cw_core/pending_transaction.dart';
4 import 'package:cw_evm/contract/erc20.dart';
5 import 'package:cw_evm/contract/oft.dart';
6 import 'package:cw_evm/evm_chain_transaction_priority.dart';
7 import 'package:cw_evm/utils/evm_chain_utils.dart';
8 import 'package:cw_evm/evm_chain_wallet.dart';
9 import 'package:cw_evm/usdt0/usdt0_config.dart';
10 import 'package:cw_evm/usdt0/usdt0_quote.dart';
11 import 'package:web3dart/web3dart.dart' as web3;
12
13 class USDT0Service {
14 static Future<USDT0Quote> quoteCrossChainTransfer({
15 required web3.Web3Client client,
16 required int sourceChainId,
17 required int destinationChainId,
18 required BigInt amount,
19 required String recipientAddress,
20 BigInt? minAmount,
21 }) async {
22 final min = minAmount ?? BigInt.zero;
23 final oftAddress = USDT0Config.getOftContractAddress(sourceChainId);
24 final dstEid = USDT0Config.getEndpointId(destinationChainId);
25
26 if (oftAddress == null || dstEid == null) {
27 throw Exception(
28 'USDT0 not supported for chain $sourceChainId -> $destinationChainId',
29 );
30 }
31
32 final toBytes32 = addressToBytes32(recipientAddress);
33 final oft = OFT(
34 address: web3.EthereumAddress.fromHex(oftAddress),
35 client: client,
36 );
37
38 return oft.quoteSend(
39 dstEid: dstEid,
40 toBytes32: toBytes32,
41 amountLD: amount,
42 minAmountLD: min,
43 payInLzToken: false,
44 );
45 }
46
47 static Future<PendingTransaction> executeCrossChainTransfer({
48 required EVMChainWallet wallet,
49 required int sourceChainId,
50 required int destinationChainId,
51 required BigInt amount,
52 required String recipientAddress,
53 required USDT0Quote quote,
54 required Erc20Token token,
55 required EVMChainTransactionPriority priority,
56 bool useBlinkProtection = true,
57 }) async {
58 final oftAddress = USDT0Config.getOftContractAddress(sourceChainId);
59 final dstEid = USDT0Config.getEndpointId(destinationChainId);
60
61 if (oftAddress == null || dstEid == null) {
62 throw Exception(
63 'USDT0 not supported for chain $sourceChainId -> $destinationChainId',
64 );
65 }
66
67 if (sourceChainId == USDT0Config.ethereumChainId) {
68 final adapter = USDT0Config.getOftAdapterAddress(sourceChainId);
69 if (adapter != null) {
70 final needsApproval = await _isApprovalRequired(
71 wallet: wallet,
72 token: token,
73 spender: adapter,
74 amount: amount,
75 );
76
77 if (needsApproval) {
78 final maxUint = BigInt.parse(
79 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
80 radix: 16,
81 );
82
83 final pendingApproval = await wallet.createApprovalTransaction(
84 Money(maxUint, token),
85 adapter,
86 priority,
87 useBlinkProtection: useBlinkProtection,
88 );
89 await pendingApproval.commit();
90 }
91 }
92 }
93
94 final client = wallet.getWeb3Client();
95 if (client == null) {
96 throw StateError('Wallet not connected to node');
97 }
98
99 final toBytes32 = addressToBytes32(recipientAddress);
100 final oft = OFT(
101 address: web3.EthereumAddress.fromHex(oftAddress),
102 client: client,
103 );
104
105 final encoded = oft.encodeSend(
106 dstEid: dstEid,
107 toBytes32: toBytes32,
108 amountLD: amount,
109 minAmountLD: BigInt.zero,
110 nativeFee: quote.nativeFee,
111 lzTokenFee: quote.lzTokenFee,
112 refundAddress: wallet.walletAddresses.primaryAddress,
113 );
114
115 return wallet.createCallDataTransaction(
116 oftAddress,
117 encoded.dataHex,
118 Money(encoded.valueWei, token),
119 priority,
120 token.contractAddress,
121 amount,
122 useBlinkProtection: useBlinkProtection,
123 );
124 }
125
126 static Future<bool> _isApprovalRequired({
127 required EVMChainWallet wallet,
128 required Erc20Token token,
129 required String spender,
130 required BigInt amount,
131 }) async {
132 final client = wallet.getWeb3Client();
133 if (client == null) return true;
134
135 final erc20 = ERC20(
136 address: web3.EthereumAddress.fromHex(token.contractAddress),
137 client: client,
138 );
139 final current = await erc20.allowance(
140 web3.EthereumAddress.fromHex(wallet.walletAddresses.primaryAddress),
141 web3.EthereumAddress.fromHex(spender),
142 );
143 return current < amount;
144 }
145 }