@reown/appkit-core-react-native 1.1.1 → 1.2.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/lib/commonjs/controllers/ApiController.js +1 -1
- package/lib/commonjs/controllers/BlockchainApiController.js +107 -21
- package/lib/commonjs/controllers/BlockchainApiController.js.map +1 -1
- package/lib/commonjs/controllers/ConnectionController.js +4 -2
- package/lib/commonjs/controllers/ConnectionController.js.map +1 -1
- package/lib/commonjs/controllers/NetworkController.js +6 -0
- package/lib/commonjs/controllers/NetworkController.js.map +1 -1
- package/lib/commonjs/controllers/RouterController.js.map +1 -1
- package/lib/commonjs/controllers/SnackController.js +5 -0
- package/lib/commonjs/controllers/SnackController.js.map +1 -1
- package/lib/commonjs/controllers/SwapController.js +578 -6
- package/lib/commonjs/controllers/SwapController.js.map +1 -1
- package/lib/commonjs/controllers/ThemeController.js +1 -1
- package/lib/commonjs/controllers/ThemeController.js.map +1 -1
- package/lib/commonjs/index.js +14 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/utils/ConnectionUtil.js +33 -0
- package/lib/commonjs/utils/ConnectionUtil.js.map +1 -0
- package/lib/commonjs/utils/ConstantsUtil.js +29 -0
- package/lib/commonjs/utils/ConstantsUtil.js.map +1 -1
- package/lib/commonjs/utils/CoreHelperUtil.js +12 -12
- package/lib/commonjs/utils/CoreHelperUtil.js.map +1 -1
- package/lib/commonjs/utils/NetworkUtil.js +46 -0
- package/lib/commonjs/utils/NetworkUtil.js.map +1 -0
- package/lib/commonjs/utils/RouterUtil.js +1 -1
- package/lib/commonjs/utils/RouterUtil.js.map +1 -1
- package/lib/commonjs/utils/SwapApiUtil.js +58 -0
- package/lib/commonjs/utils/SwapApiUtil.js.map +1 -1
- package/lib/commonjs/utils/SwapCalculationUtil.js +73 -0
- package/lib/commonjs/utils/SwapCalculationUtil.js.map +1 -1
- package/lib/module/controllers/ApiController.js +1 -1
- package/lib/module/controllers/BlockchainApiController.js +107 -21
- package/lib/module/controllers/BlockchainApiController.js.map +1 -1
- package/lib/module/controllers/ConnectionController.js +4 -2
- package/lib/module/controllers/ConnectionController.js.map +1 -1
- package/lib/module/controllers/NetworkController.js +6 -0
- package/lib/module/controllers/NetworkController.js.map +1 -1
- package/lib/module/controllers/RouterController.js.map +1 -1
- package/lib/module/controllers/SnackController.js +5 -0
- package/lib/module/controllers/SnackController.js.map +1 -1
- package/lib/module/controllers/SwapController.js +578 -6
- package/lib/module/controllers/SwapController.js.map +1 -1
- package/lib/module/controllers/ThemeController.js +1 -1
- package/lib/module/controllers/ThemeController.js.map +1 -1
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/ConnectionUtil.js +27 -0
- package/lib/module/utils/ConnectionUtil.js.map +1 -0
- package/lib/module/utils/ConstantsUtil.js +29 -0
- package/lib/module/utils/ConstantsUtil.js.map +1 -1
- package/lib/module/utils/CoreHelperUtil.js +12 -12
- package/lib/module/utils/CoreHelperUtil.js.map +1 -1
- package/lib/module/utils/NetworkUtil.js +40 -0
- package/lib/module/utils/NetworkUtil.js.map +1 -0
- package/lib/module/utils/RouterUtil.js +1 -1
- package/lib/module/utils/RouterUtil.js.map +1 -1
- package/lib/module/utils/SwapApiUtil.js +58 -0
- package/lib/module/utils/SwapApiUtil.js.map +1 -1
- package/lib/module/utils/SwapCalculationUtil.js +73 -1
- package/lib/module/utils/SwapCalculationUtil.js.map +1 -1
- package/lib/typescript/controllers/ApiController.d.ts +1 -1
- package/lib/typescript/controllers/BlockchainApiController.d.ts +6 -1
- package/lib/typescript/controllers/BlockchainApiController.d.ts.map +1 -1
- package/lib/typescript/controllers/ConnectionController.d.ts +3 -1
- package/lib/typescript/controllers/ConnectionController.d.ts.map +1 -1
- package/lib/typescript/controllers/NetworkController.d.ts +1 -0
- package/lib/typescript/controllers/NetworkController.d.ts.map +1 -1
- package/lib/typescript/controllers/RouterController.d.ts +3 -2
- package/lib/typescript/controllers/RouterController.d.ts.map +1 -1
- package/lib/typescript/controllers/SnackController.d.ts +2 -1
- package/lib/typescript/controllers/SnackController.d.ts.map +1 -1
- package/lib/typescript/controllers/SwapController.d.ts +87 -0
- package/lib/typescript/controllers/SwapController.d.ts.map +1 -1
- package/lib/typescript/controllers/ThemeController.d.ts +2 -2
- package/lib/typescript/controllers/ThemeController.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +2 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/utils/ConnectionUtil.d.ts +4 -0
- package/lib/typescript/utils/ConnectionUtil.d.ts.map +1 -0
- package/lib/typescript/utils/ConstantsUtil.d.ts +4 -0
- package/lib/typescript/utils/ConstantsUtil.d.ts.map +1 -1
- package/lib/typescript/utils/CoreHelperUtil.d.ts +2 -2
- package/lib/typescript/utils/CoreHelperUtil.d.ts.map +1 -1
- package/lib/typescript/utils/NetworkUtil.d.ts +8 -0
- package/lib/typescript/utils/NetworkUtil.d.ts.map +1 -0
- package/lib/typescript/utils/RouterUtil.d.ts.map +1 -1
- package/lib/typescript/utils/SwapApiUtil.d.ts +8 -0
- package/lib/typescript/utils/SwapApiUtil.d.ts.map +1 -1
- package/lib/typescript/utils/SwapCalculationUtil.d.ts +19 -0
- package/lib/typescript/utils/SwapCalculationUtil.d.ts.map +1 -1
- package/lib/typescript/utils/TypeUtil.d.ts +146 -6
- package/lib/typescript/utils/TypeUtil.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/controllers/ApiController.ts +1 -1
- package/src/controllers/BlockchainApiController.ts +114 -17
- package/src/controllers/ConnectionController.ts +6 -2
- package/src/controllers/NetworkController.ts +8 -0
- package/src/controllers/RouterController.ts +6 -1
- package/src/controllers/SnackController.ts +7 -1
- package/src/controllers/SwapController.ts +759 -6
- package/src/controllers/ThemeController.ts +3 -3
- package/src/index.ts +2 -0
- package/src/utils/ConnectionUtil.ts +27 -0
- package/src/utils/ConstantsUtil.ts +120 -0
- package/src/utils/CoreHelperUtil.ts +20 -15
- package/src/utils/NetworkUtil.ts +33 -0
- package/src/utils/RouterUtil.ts +4 -1
- package/src/utils/SwapApiUtil.ts +89 -0
- package/src/utils/SwapCalculationUtil.ts +125 -0
- package/src/utils/TypeUtil.ts +169 -10
|
@@ -6,28 +6,76 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.TO_AMOUNT_DECIMALS = exports.SwapController = exports.INITIAL_GAS_LIMIT = void 0;
|
|
7
7
|
var _utils = require("valtio/utils");
|
|
8
8
|
var _valtio = require("valtio");
|
|
9
|
+
var _appkitCommonReactNative = require("@reown/appkit-common-react-native");
|
|
9
10
|
var _ConstantsUtil = require("../utils/ConstantsUtil");
|
|
10
11
|
var _SwapApiUtil = require("../utils/SwapApiUtil");
|
|
11
12
|
var _NetworkController = require("./NetworkController");
|
|
12
13
|
var _BlockchainApiController = require("./BlockchainApiController");
|
|
13
14
|
var _OptionsController = require("./OptionsController");
|
|
14
15
|
var _SwapCalculationUtil = require("../utils/SwapCalculationUtil");
|
|
16
|
+
var _SnackController = require("./SnackController");
|
|
17
|
+
var _RouterController = require("./RouterController");
|
|
18
|
+
var _ConnectorController = require("./ConnectorController");
|
|
19
|
+
var _AccountController = require("./AccountController");
|
|
20
|
+
var _CoreHelperUtil = require("../utils/CoreHelperUtil");
|
|
21
|
+
var _ConnectionController = require("./ConnectionController");
|
|
22
|
+
var _TransactionsController = require("./TransactionsController");
|
|
23
|
+
var _EventsController = require("./EventsController");
|
|
15
24
|
// -- Constants ---------------------------------------- //
|
|
16
25
|
const INITIAL_GAS_LIMIT = exports.INITIAL_GAS_LIMIT = 150000;
|
|
17
26
|
const TO_AMOUNT_DECIMALS = exports.TO_AMOUNT_DECIMALS = 6;
|
|
18
27
|
|
|
19
28
|
// -- Types --------------------------------------------- //
|
|
20
29
|
|
|
30
|
+
class TransactionError extends Error {
|
|
31
|
+
constructor(message, shortMessage) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = 'TransactionError';
|
|
34
|
+
this.shortMessage = shortMessage;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
21
37
|
// -- State --------------------------------------------- //
|
|
22
38
|
const initialState = {
|
|
39
|
+
// Loading states
|
|
40
|
+
initializing: false,
|
|
41
|
+
initialized: false,
|
|
42
|
+
loadingPrices: false,
|
|
43
|
+
loadingQuote: false,
|
|
44
|
+
loadingApprovalTransaction: false,
|
|
45
|
+
loadingBuildTransaction: false,
|
|
46
|
+
loadingTransaction: false,
|
|
47
|
+
// Error states
|
|
48
|
+
fetchError: false,
|
|
49
|
+
// Approval & Swap transaction states
|
|
50
|
+
approvalTransaction: undefined,
|
|
51
|
+
swapTransaction: undefined,
|
|
52
|
+
transactionError: undefined,
|
|
23
53
|
// Input values
|
|
54
|
+
sourceToken: undefined,
|
|
55
|
+
sourceTokenAmount: '',
|
|
56
|
+
sourceTokenPriceInUSD: 0,
|
|
57
|
+
toToken: undefined,
|
|
58
|
+
toTokenAmount: '',
|
|
59
|
+
toTokenPriceInUSD: 0,
|
|
24
60
|
networkPrice: '0',
|
|
61
|
+
networkBalanceInUSD: '0',
|
|
25
62
|
networkTokenSymbol: '',
|
|
63
|
+
inputError: undefined,
|
|
64
|
+
// Request values
|
|
65
|
+
slippage: _ConstantsUtil.ConstantsUtil.CONVERT_SLIPPAGE_TOLERANCE,
|
|
26
66
|
// Tokens
|
|
67
|
+
tokens: undefined,
|
|
68
|
+
popularTokens: undefined,
|
|
69
|
+
suggestedTokens: undefined,
|
|
70
|
+
foundTokens: undefined,
|
|
71
|
+
myTokensWithBalance: undefined,
|
|
27
72
|
tokensPriceMap: {},
|
|
28
73
|
// Calculations
|
|
29
74
|
gasFee: '0',
|
|
30
|
-
gasPriceInUSD: 0
|
|
75
|
+
gasPriceInUSD: 0,
|
|
76
|
+
priceImpact: undefined,
|
|
77
|
+
maxSlippage: undefined,
|
|
78
|
+
providerFee: undefined
|
|
31
79
|
};
|
|
32
80
|
const state = (0, _valtio.proxy)(initialState);
|
|
33
81
|
|
|
@@ -41,18 +89,164 @@ const SwapController = exports.SwapController = {
|
|
|
41
89
|
return (0, _utils.subscribeKey)(state, key, callback);
|
|
42
90
|
},
|
|
43
91
|
getParams() {
|
|
44
|
-
const
|
|
45
|
-
const
|
|
92
|
+
const caipAddress = _AccountController.AccountController.state.caipAddress;
|
|
93
|
+
const address = _CoreHelperUtil.CoreHelperUtil.getPlainAddress(caipAddress);
|
|
94
|
+
const networkAddress = _NetworkController.NetworkController.getActiveNetworkTokenAddress();
|
|
95
|
+
const type = _ConnectorController.ConnectorController.state.connectedConnector;
|
|
96
|
+
if (!address) {
|
|
97
|
+
throw new Error('No address found to swap the tokens from.');
|
|
98
|
+
}
|
|
99
|
+
const invalidToToken = !state.toToken?.address || !state.toToken?.decimals;
|
|
100
|
+
const invalidSourceToken = !state.sourceToken?.address || !state.sourceToken?.decimals || state.sourceToken.address === state.toToken?.address || !_appkitCommonReactNative.NumberUtil.bigNumber(state.sourceTokenAmount).isGreaterThan(0);
|
|
101
|
+
const invalidSourceTokenAmount = !state.sourceTokenAmount;
|
|
46
102
|
return {
|
|
47
|
-
networkAddress
|
|
103
|
+
networkAddress,
|
|
104
|
+
fromAddress: address,
|
|
105
|
+
fromCaipAddress: caipAddress,
|
|
106
|
+
sourceTokenAddress: state.sourceToken?.address,
|
|
107
|
+
toTokenAddress: state.toToken?.address,
|
|
108
|
+
toTokenAmount: state.toTokenAmount,
|
|
109
|
+
toTokenDecimals: state.toToken?.decimals,
|
|
110
|
+
sourceTokenAmount: state.sourceTokenAmount,
|
|
111
|
+
sourceTokenDecimals: state.sourceToken?.decimals,
|
|
112
|
+
invalidToToken,
|
|
113
|
+
invalidSourceToken,
|
|
114
|
+
invalidSourceTokenAmount,
|
|
115
|
+
availableToSwap: caipAddress && !invalidToToken && !invalidSourceToken && !invalidSourceTokenAmount,
|
|
116
|
+
isAuthConnector: type === 'AUTH'
|
|
48
117
|
};
|
|
49
118
|
},
|
|
119
|
+
switchTokens() {
|
|
120
|
+
if (state.initializing || !state.initialized) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
let newSourceToken = state.toToken ? {
|
|
124
|
+
...state.toToken
|
|
125
|
+
} : undefined;
|
|
126
|
+
const sourceTokenWithBalance = state.myTokensWithBalance?.find(token => token.address === newSourceToken?.address);
|
|
127
|
+
if (sourceTokenWithBalance) {
|
|
128
|
+
newSourceToken = sourceTokenWithBalance;
|
|
129
|
+
}
|
|
130
|
+
const newToToken = state.sourceToken ? {
|
|
131
|
+
...state.sourceToken
|
|
132
|
+
} : undefined;
|
|
133
|
+
const newSourceTokenAmount = newSourceToken && state.toTokenAmount === '' ? '1' : state.toTokenAmount;
|
|
134
|
+
this.setSourceToken(newSourceToken);
|
|
135
|
+
this.setToToken(newToToken);
|
|
136
|
+
this.setSourceTokenAmount(newSourceTokenAmount);
|
|
137
|
+
this.setToTokenAmount('');
|
|
138
|
+
this.swapTokens();
|
|
139
|
+
},
|
|
50
140
|
resetState() {
|
|
141
|
+
state.myTokensWithBalance = initialState.myTokensWithBalance;
|
|
51
142
|
state.tokensPriceMap = initialState.tokensPriceMap;
|
|
143
|
+
state.initialized = initialState.initialized;
|
|
144
|
+
state.sourceToken = initialState.sourceToken;
|
|
145
|
+
state.sourceTokenAmount = initialState.sourceTokenAmount;
|
|
146
|
+
state.sourceTokenPriceInUSD = initialState.sourceTokenPriceInUSD;
|
|
147
|
+
state.toToken = initialState.toToken;
|
|
148
|
+
state.toTokenAmount = initialState.toTokenAmount;
|
|
149
|
+
state.toTokenPriceInUSD = initialState.toTokenPriceInUSD;
|
|
52
150
|
state.networkPrice = initialState.networkPrice;
|
|
53
151
|
state.networkTokenSymbol = initialState.networkTokenSymbol;
|
|
152
|
+
state.networkBalanceInUSD = initialState.networkBalanceInUSD;
|
|
153
|
+
state.inputError = initialState.inputError;
|
|
154
|
+
},
|
|
155
|
+
async fetchTokens() {
|
|
156
|
+
const {
|
|
157
|
+
networkAddress
|
|
158
|
+
} = this.getParams();
|
|
159
|
+
await this.getTokenList();
|
|
160
|
+
await this.getNetworkTokenPrice();
|
|
161
|
+
await this.getMyTokensWithBalance();
|
|
162
|
+
const networkToken = state.tokens?.find(token => token.address === networkAddress);
|
|
163
|
+
if (networkToken) {
|
|
164
|
+
state.networkTokenSymbol = networkToken.symbol;
|
|
165
|
+
}
|
|
166
|
+
const sourceToken = state.myTokensWithBalance?.find(token => token.address.startsWith(networkAddress)) || state.myTokensWithBalance?.[0];
|
|
167
|
+
this.setSourceToken(sourceToken);
|
|
168
|
+
this.setSourceTokenAmount('1');
|
|
169
|
+
},
|
|
170
|
+
async getTokenList() {
|
|
171
|
+
const tokens = await _SwapApiUtil.SwapApiUtil.getTokenList();
|
|
172
|
+
state.tokens = tokens;
|
|
173
|
+
state.popularTokens = tokens.sort((aTokenInfo, bTokenInfo) => {
|
|
174
|
+
if (aTokenInfo.symbol < bTokenInfo.symbol) {
|
|
175
|
+
return -1;
|
|
176
|
+
}
|
|
177
|
+
if (aTokenInfo.symbol > bTokenInfo.symbol) {
|
|
178
|
+
return 1;
|
|
179
|
+
}
|
|
180
|
+
return 0;
|
|
181
|
+
});
|
|
182
|
+
state.suggestedTokens = tokens.filter(token => {
|
|
183
|
+
if (_ConstantsUtil.ConstantsUtil.SWAP_SUGGESTED_TOKENS.includes(token.symbol)) {
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
return false;
|
|
187
|
+
}, {});
|
|
188
|
+
},
|
|
189
|
+
async getMyTokensWithBalance(forceUpdate) {
|
|
190
|
+
const balances = await _SwapApiUtil.SwapApiUtil.getMyTokensWithBalance(forceUpdate);
|
|
191
|
+
if (!balances) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
await this.getInitialGasPrice();
|
|
195
|
+
this.setBalances(balances);
|
|
196
|
+
},
|
|
197
|
+
getFilteredPopularTokens() {
|
|
198
|
+
return state.popularTokens?.filter(token => !state.myTokensWithBalance?.some(t => t.address === token.address));
|
|
199
|
+
},
|
|
200
|
+
setSourceToken(sourceToken) {
|
|
201
|
+
if (!sourceToken) {
|
|
202
|
+
state.sourceToken = sourceToken;
|
|
203
|
+
state.sourceTokenAmount = '';
|
|
204
|
+
state.sourceTokenPriceInUSD = 0;
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
state.sourceToken = sourceToken;
|
|
208
|
+
this.setTokenPrice(sourceToken.address, 'sourceToken');
|
|
209
|
+
},
|
|
210
|
+
setSourceTokenAmount(amount) {
|
|
211
|
+
state.sourceTokenAmount = amount;
|
|
212
|
+
if (amount === '') {
|
|
213
|
+
state.toTokenAmount = '';
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
async initializeState() {
|
|
217
|
+
if (state.initializing) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
state.initializing = true;
|
|
221
|
+
if (!state.initialized) {
|
|
222
|
+
try {
|
|
223
|
+
await this.fetchTokens();
|
|
224
|
+
state.initialized = true;
|
|
225
|
+
} catch (error) {
|
|
226
|
+
state.initialized = false;
|
|
227
|
+
_SnackController.SnackController.showError('Failed to initialize swap');
|
|
228
|
+
_RouterController.RouterController.goBack();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
state.initializing = false;
|
|
232
|
+
},
|
|
233
|
+
async getAddressPrice(address) {
|
|
234
|
+
const existPrice = state.tokensPriceMap[address];
|
|
235
|
+
if (existPrice) {
|
|
236
|
+
return existPrice;
|
|
237
|
+
}
|
|
238
|
+
const response = await _BlockchainApiController.BlockchainApiController.fetchTokenPrice({
|
|
239
|
+
projectId: _OptionsController.OptionsController.state.projectId,
|
|
240
|
+
addresses: [address]
|
|
241
|
+
});
|
|
242
|
+
const fungibles = response?.fungibles || [];
|
|
243
|
+
const allTokens = [...(state.tokens || []), ...(state.myTokensWithBalance || [])];
|
|
244
|
+
const symbol = allTokens?.find(token => token.address === address)?.symbol;
|
|
245
|
+
const price = fungibles.find(p => p.symbol.toLowerCase() === symbol?.toLowerCase())?.price || 0;
|
|
246
|
+
const priceAsFloat = parseFloat(price.toString());
|
|
247
|
+
state.tokensPriceMap[address] = priceAsFloat;
|
|
248
|
+
return priceAsFloat;
|
|
54
249
|
},
|
|
55
|
-
//this
|
|
56
250
|
async getNetworkTokenPrice() {
|
|
57
251
|
const {
|
|
58
252
|
networkAddress
|
|
@@ -67,7 +261,6 @@ const SwapController = exports.SwapController = {
|
|
|
67
261
|
state.networkTokenSymbol = token?.symbol || '';
|
|
68
262
|
state.networkPrice = price;
|
|
69
263
|
},
|
|
70
|
-
//this
|
|
71
264
|
async getInitialGasPrice() {
|
|
72
265
|
const res = await _SwapApiUtil.SwapApiUtil.fetchGasPrice();
|
|
73
266
|
if (!res) {
|
|
@@ -86,6 +279,385 @@ const SwapController = exports.SwapController = {
|
|
|
86
279
|
gasPrice: gasFee,
|
|
87
280
|
gasPriceInUSD: state.gasPriceInUSD
|
|
88
281
|
};
|
|
282
|
+
},
|
|
283
|
+
getProviderFeePrice() {
|
|
284
|
+
return _SwapCalculationUtil.SwapCalculationUtil.getProviderFeePrice(state.sourceTokenAmount, state.sourceTokenPriceInUSD);
|
|
285
|
+
},
|
|
286
|
+
setBalances(balances) {
|
|
287
|
+
const {
|
|
288
|
+
networkAddress
|
|
289
|
+
} = this.getParams();
|
|
290
|
+
const caipNetwork = _NetworkController.NetworkController.state.caipNetwork;
|
|
291
|
+
if (!caipNetwork) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
const networkToken = balances.find(token => token.address === networkAddress);
|
|
295
|
+
balances.forEach(token => {
|
|
296
|
+
state.tokensPriceMap[token.address] = token.price || 0;
|
|
297
|
+
});
|
|
298
|
+
state.myTokensWithBalance = balances.filter(token => token.address?.startsWith(caipNetwork.id));
|
|
299
|
+
state.networkBalanceInUSD = networkToken ? _appkitCommonReactNative.NumberUtil.multiply(networkToken.quantity.numeric, networkToken.price).toString() : '0';
|
|
300
|
+
},
|
|
301
|
+
setToToken(toToken) {
|
|
302
|
+
if (!toToken) {
|
|
303
|
+
state.toToken = toToken;
|
|
304
|
+
state.toTokenAmount = '';
|
|
305
|
+
state.toTokenPriceInUSD = 0;
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
state.toToken = toToken;
|
|
309
|
+
this.setTokenPrice(toToken.address, 'toToken');
|
|
310
|
+
},
|
|
311
|
+
setToTokenAmount(amount) {
|
|
312
|
+
state.toTokenAmount = amount ? _appkitCommonReactNative.NumberUtil.formatNumberToLocalString(amount, TO_AMOUNT_DECIMALS) : '';
|
|
313
|
+
},
|
|
314
|
+
async setTokenPrice(address, target) {
|
|
315
|
+
let price = state.tokensPriceMap[address] || 0;
|
|
316
|
+
if (!price) {
|
|
317
|
+
state.loadingPrices = true;
|
|
318
|
+
price = await this.getAddressPrice(address);
|
|
319
|
+
}
|
|
320
|
+
if (target === 'sourceToken') {
|
|
321
|
+
state.sourceTokenPriceInUSD = price;
|
|
322
|
+
} else if (target === 'toToken') {
|
|
323
|
+
state.toTokenPriceInUSD = price;
|
|
324
|
+
}
|
|
325
|
+
if (state.loadingPrices) {
|
|
326
|
+
state.loadingPrices = false;
|
|
327
|
+
}
|
|
328
|
+
if (this.getParams().availableToSwap) {
|
|
329
|
+
this.swapTokens();
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
// -- Swap ---------------------------------------------- //
|
|
333
|
+
async swapTokens() {
|
|
334
|
+
const address = _AccountController.AccountController.state.address;
|
|
335
|
+
const sourceToken = state.sourceToken;
|
|
336
|
+
const toToken = state.toToken;
|
|
337
|
+
const haveSourceTokenAmount = _appkitCommonReactNative.NumberUtil.bigNumber(state.sourceTokenAmount).isGreaterThan(0);
|
|
338
|
+
if (!toToken || !sourceToken || state.loadingPrices || !haveSourceTokenAmount) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
state.loadingQuote = true;
|
|
342
|
+
const amountDecimal = _appkitCommonReactNative.NumberUtil.bigNumber(state.sourceTokenAmount).multipliedBy(10 ** sourceToken.decimals).integerValue();
|
|
343
|
+
const quoteResponse = await _BlockchainApiController.BlockchainApiController.fetchSwapQuote({
|
|
344
|
+
userAddress: address,
|
|
345
|
+
projectId: _OptionsController.OptionsController.state.projectId,
|
|
346
|
+
from: sourceToken.address,
|
|
347
|
+
to: toToken.address,
|
|
348
|
+
gasPrice: state.gasFee,
|
|
349
|
+
amount: amountDecimal.toString()
|
|
350
|
+
});
|
|
351
|
+
state.loadingQuote = false;
|
|
352
|
+
const quoteToAmount = quoteResponse?.quotes?.[0]?.toAmount;
|
|
353
|
+
if (!quoteToAmount) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
const toTokenAmount = _appkitCommonReactNative.NumberUtil.bigNumber(quoteToAmount).dividedBy(10 ** toToken.decimals).toString();
|
|
357
|
+
this.setToTokenAmount(toTokenAmount);
|
|
358
|
+
const isInsufficientToken = this.hasInsufficientToken(state.sourceTokenAmount, sourceToken.address);
|
|
359
|
+
if (isInsufficientToken) {
|
|
360
|
+
state.inputError = 'Insufficient balance';
|
|
361
|
+
} else {
|
|
362
|
+
state.inputError = undefined;
|
|
363
|
+
this.setTransactionDetails();
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
// -- Create Transactions -------------------------------------- //
|
|
367
|
+
async getTransaction() {
|
|
368
|
+
const {
|
|
369
|
+
fromCaipAddress,
|
|
370
|
+
availableToSwap
|
|
371
|
+
} = this.getParams();
|
|
372
|
+
const sourceToken = state.sourceToken;
|
|
373
|
+
const toToken = state.toToken;
|
|
374
|
+
if (!fromCaipAddress || !availableToSwap || !sourceToken || !toToken || state.loadingQuote) {
|
|
375
|
+
return undefined;
|
|
376
|
+
}
|
|
377
|
+
try {
|
|
378
|
+
state.loadingBuildTransaction = true;
|
|
379
|
+
const hasAllowance = await _SwapApiUtil.SwapApiUtil.fetchSwapAllowance({
|
|
380
|
+
userAddress: fromCaipAddress,
|
|
381
|
+
tokenAddress: sourceToken.address,
|
|
382
|
+
sourceTokenAmount: state.sourceTokenAmount,
|
|
383
|
+
sourceTokenDecimals: sourceToken.decimals
|
|
384
|
+
});
|
|
385
|
+
let transaction;
|
|
386
|
+
if (hasAllowance) {
|
|
387
|
+
transaction = await this.createSwapTransaction();
|
|
388
|
+
} else {
|
|
389
|
+
transaction = await this.createAllowanceTransaction();
|
|
390
|
+
}
|
|
391
|
+
state.loadingBuildTransaction = false;
|
|
392
|
+
state.fetchError = false;
|
|
393
|
+
return transaction;
|
|
394
|
+
} catch (error) {
|
|
395
|
+
_RouterController.RouterController.goBack();
|
|
396
|
+
_SnackController.SnackController.showError('Failed to check allowance');
|
|
397
|
+
state.loadingBuildTransaction = false;
|
|
398
|
+
state.approvalTransaction = undefined;
|
|
399
|
+
state.swapTransaction = undefined;
|
|
400
|
+
state.fetchError = true;
|
|
401
|
+
return undefined;
|
|
402
|
+
}
|
|
403
|
+
},
|
|
404
|
+
async createAllowanceTransaction() {
|
|
405
|
+
const {
|
|
406
|
+
fromCaipAddress,
|
|
407
|
+
fromAddress,
|
|
408
|
+
sourceTokenAddress,
|
|
409
|
+
toTokenAddress
|
|
410
|
+
} = this.getParams();
|
|
411
|
+
if (!fromCaipAddress || !toTokenAddress) {
|
|
412
|
+
return undefined;
|
|
413
|
+
}
|
|
414
|
+
if (!sourceTokenAddress) {
|
|
415
|
+
throw new Error('createAllowanceTransaction - No source token address found.');
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
const response = await _BlockchainApiController.BlockchainApiController.generateApproveCalldata({
|
|
419
|
+
projectId: _OptionsController.OptionsController.state.projectId,
|
|
420
|
+
from: sourceTokenAddress,
|
|
421
|
+
to: toTokenAddress,
|
|
422
|
+
userAddress: fromCaipAddress
|
|
423
|
+
});
|
|
424
|
+
if (!response) {
|
|
425
|
+
throw new Error('createAllowanceTransaction - No response from generateApproveCalldata');
|
|
426
|
+
}
|
|
427
|
+
const gasLimit = await _ConnectionController.ConnectionController.estimateGas({
|
|
428
|
+
address: fromAddress,
|
|
429
|
+
to: _CoreHelperUtil.CoreHelperUtil.getPlainAddress(response.tx.to),
|
|
430
|
+
data: response.tx.data
|
|
431
|
+
});
|
|
432
|
+
const transaction = {
|
|
433
|
+
data: response.tx.data,
|
|
434
|
+
to: _CoreHelperUtil.CoreHelperUtil.getPlainAddress(response.tx.from),
|
|
435
|
+
gas: gasLimit,
|
|
436
|
+
gasPrice: BigInt(response.tx.eip155.gasPrice),
|
|
437
|
+
value: BigInt(response.tx.value),
|
|
438
|
+
toAmount: state.toTokenAmount
|
|
439
|
+
};
|
|
440
|
+
state.swapTransaction = undefined;
|
|
441
|
+
state.approvalTransaction = {
|
|
442
|
+
data: transaction.data,
|
|
443
|
+
to: transaction.to,
|
|
444
|
+
gas: transaction.gas ?? BigInt(0),
|
|
445
|
+
gasPrice: transaction.gasPrice,
|
|
446
|
+
value: transaction.value,
|
|
447
|
+
toAmount: transaction.toAmount
|
|
448
|
+
};
|
|
449
|
+
return {
|
|
450
|
+
data: transaction.data,
|
|
451
|
+
to: transaction.to,
|
|
452
|
+
gas: transaction.gas ?? BigInt(0),
|
|
453
|
+
gasPrice: transaction.gasPrice,
|
|
454
|
+
value: transaction.value,
|
|
455
|
+
toAmount: transaction.toAmount
|
|
456
|
+
};
|
|
457
|
+
} catch (error) {
|
|
458
|
+
_RouterController.RouterController.goBack();
|
|
459
|
+
_SnackController.SnackController.showError('Failed to create approval transaction');
|
|
460
|
+
state.approvalTransaction = undefined;
|
|
461
|
+
state.swapTransaction = undefined;
|
|
462
|
+
state.fetchError = true;
|
|
463
|
+
return undefined;
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
async createSwapTransaction() {
|
|
467
|
+
const {
|
|
468
|
+
networkAddress,
|
|
469
|
+
fromCaipAddress,
|
|
470
|
+
sourceTokenAmount
|
|
471
|
+
} = this.getParams();
|
|
472
|
+
const sourceToken = state.sourceToken;
|
|
473
|
+
const toToken = state.toToken;
|
|
474
|
+
if (!fromCaipAddress || !sourceTokenAmount || !sourceToken || !toToken) {
|
|
475
|
+
return undefined;
|
|
476
|
+
}
|
|
477
|
+
const amount = _ConnectionController.ConnectionController.parseUnits(sourceTokenAmount, sourceToken.decimals)?.toString();
|
|
478
|
+
try {
|
|
479
|
+
const response = await _BlockchainApiController.BlockchainApiController.generateSwapCalldata({
|
|
480
|
+
projectId: _OptionsController.OptionsController.state.projectId,
|
|
481
|
+
userAddress: fromCaipAddress,
|
|
482
|
+
from: sourceToken.address,
|
|
483
|
+
to: toToken.address,
|
|
484
|
+
amount: amount
|
|
485
|
+
});
|
|
486
|
+
if (!response) {
|
|
487
|
+
throw new Error('createSwapTransaction - No response from generateSwapCalldata');
|
|
488
|
+
}
|
|
489
|
+
const isSourceNetworkToken = sourceToken.address === networkAddress;
|
|
490
|
+
const gas = BigInt(response.tx.eip155.gas);
|
|
491
|
+
const gasPrice = BigInt(response.tx.eip155.gasPrice);
|
|
492
|
+
const transaction = {
|
|
493
|
+
data: response.tx.data,
|
|
494
|
+
to: _CoreHelperUtil.CoreHelperUtil.getPlainAddress(response.tx.to),
|
|
495
|
+
gas,
|
|
496
|
+
gasPrice,
|
|
497
|
+
value: isSourceNetworkToken ? BigInt(amount ?? '0') : BigInt('0'),
|
|
498
|
+
toAmount: state.toTokenAmount
|
|
499
|
+
};
|
|
500
|
+
state.gasPriceInUSD = _SwapCalculationUtil.SwapCalculationUtil.getGasPriceInUSD(state.networkPrice, gas, gasPrice);
|
|
501
|
+
state.approvalTransaction = undefined;
|
|
502
|
+
state.swapTransaction = transaction;
|
|
503
|
+
return transaction;
|
|
504
|
+
} catch (error) {
|
|
505
|
+
_RouterController.RouterController.goBack();
|
|
506
|
+
_SnackController.SnackController.showError('Failed to create transaction');
|
|
507
|
+
state.approvalTransaction = undefined;
|
|
508
|
+
state.swapTransaction = undefined;
|
|
509
|
+
state.fetchError = true;
|
|
510
|
+
return undefined;
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
async sendTransactionForApproval(data) {
|
|
514
|
+
const {
|
|
515
|
+
fromAddress,
|
|
516
|
+
isAuthConnector
|
|
517
|
+
} = this.getParams();
|
|
518
|
+
state.loadingApprovalTransaction = true;
|
|
519
|
+
const approveLimitMessage = `Approve limit increase in your wallet`;
|
|
520
|
+
if (isAuthConnector) {
|
|
521
|
+
_RouterController.RouterController.pushTransactionStack({
|
|
522
|
+
view: null,
|
|
523
|
+
goBack: true,
|
|
524
|
+
onSuccess() {
|
|
525
|
+
_SnackController.SnackController.showLoading(approveLimitMessage);
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
} else {
|
|
529
|
+
_SnackController.SnackController.showLoading(approveLimitMessage);
|
|
530
|
+
}
|
|
531
|
+
try {
|
|
532
|
+
await _ConnectionController.ConnectionController.sendTransaction({
|
|
533
|
+
address: fromAddress,
|
|
534
|
+
to: data.to,
|
|
535
|
+
data: data.data,
|
|
536
|
+
value: BigInt(data.value),
|
|
537
|
+
gasPrice: BigInt(data.gasPrice),
|
|
538
|
+
chainNamespace: 'eip155'
|
|
539
|
+
});
|
|
540
|
+
await this.swapTokens();
|
|
541
|
+
await this.getTransaction();
|
|
542
|
+
state.approvalTransaction = undefined;
|
|
543
|
+
state.loadingApprovalTransaction = false;
|
|
544
|
+
} catch (err) {
|
|
545
|
+
const error = err;
|
|
546
|
+
state.transactionError = error?.shortMessage;
|
|
547
|
+
state.loadingApprovalTransaction = false;
|
|
548
|
+
_SnackController.SnackController.showError(error?.shortMessage ?? 'Transaction error');
|
|
549
|
+
}
|
|
550
|
+
},
|
|
551
|
+
async sendTransactionForSwap(data) {
|
|
552
|
+
if (!data) {
|
|
553
|
+
return undefined;
|
|
554
|
+
}
|
|
555
|
+
const {
|
|
556
|
+
fromAddress,
|
|
557
|
+
toTokenAmount,
|
|
558
|
+
isAuthConnector
|
|
559
|
+
} = this.getParams();
|
|
560
|
+
state.loadingTransaction = true;
|
|
561
|
+
const snackbarPendingMessage = `Swapping ${state.sourceToken?.symbol} to ${_appkitCommonReactNative.NumberUtil.formatNumberToLocalString(toTokenAmount, 3)} ${state.toToken?.symbol}`;
|
|
562
|
+
const snackbarSuccessMessage = `Swapped ${state.sourceToken?.symbol} to ${_appkitCommonReactNative.NumberUtil.formatNumberToLocalString(toTokenAmount, 3)} ${state.toToken?.symbol}`;
|
|
563
|
+
if (isAuthConnector) {
|
|
564
|
+
_RouterController.RouterController.pushTransactionStack({
|
|
565
|
+
view: 'Account',
|
|
566
|
+
goBack: false,
|
|
567
|
+
onSuccess() {
|
|
568
|
+
_SnackController.SnackController.showLoading(snackbarPendingMessage);
|
|
569
|
+
SwapController.resetState();
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
} else {
|
|
573
|
+
_SnackController.SnackController.showLoading('Confirm transaction in your wallet');
|
|
574
|
+
}
|
|
575
|
+
try {
|
|
576
|
+
const forceUpdateAddresses = [state.sourceToken?.address, state.toToken?.address].join(',');
|
|
577
|
+
const transactionHash = await _ConnectionController.ConnectionController.sendTransaction({
|
|
578
|
+
address: fromAddress,
|
|
579
|
+
to: data.to,
|
|
580
|
+
data: data.data,
|
|
581
|
+
gas: data.gas,
|
|
582
|
+
gasPrice: BigInt(data.gasPrice),
|
|
583
|
+
value: data.value,
|
|
584
|
+
chainNamespace: 'eip155'
|
|
585
|
+
});
|
|
586
|
+
state.loadingTransaction = false;
|
|
587
|
+
_SnackController.SnackController.showSuccess(snackbarSuccessMessage);
|
|
588
|
+
_EventsController.EventsController.sendEvent({
|
|
589
|
+
type: 'track',
|
|
590
|
+
event: 'SWAP_SUCCESS',
|
|
591
|
+
properties: {
|
|
592
|
+
network: _NetworkController.NetworkController.state.caipNetwork?.id || '',
|
|
593
|
+
swapFromToken: this.state.sourceToken?.symbol || '',
|
|
594
|
+
swapToToken: this.state.toToken?.symbol || '',
|
|
595
|
+
swapFromAmount: this.state.sourceTokenAmount || '',
|
|
596
|
+
swapToAmount: this.state.toTokenAmount || '',
|
|
597
|
+
isSmartAccount: _AccountController.AccountController.state.preferredAccountType === 'smartAccount'
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
SwapController.resetState();
|
|
601
|
+
if (!isAuthConnector) {
|
|
602
|
+
_RouterController.RouterController.replace('AccountDefault');
|
|
603
|
+
}
|
|
604
|
+
SwapController.getMyTokensWithBalance(forceUpdateAddresses);
|
|
605
|
+
_AccountController.AccountController.fetchTokenBalance();
|
|
606
|
+
setTimeout(() => {
|
|
607
|
+
_TransactionsController.TransactionsController.fetchTransactions(_AccountController.AccountController.state.address, true);
|
|
608
|
+
}, 5000);
|
|
609
|
+
return transactionHash;
|
|
610
|
+
} catch (err) {
|
|
611
|
+
const error = err;
|
|
612
|
+
state.transactionError = error?.shortMessage;
|
|
613
|
+
state.loadingTransaction = false;
|
|
614
|
+
_SnackController.SnackController.showError(error?.shortMessage ?? 'Transaction error');
|
|
615
|
+
_EventsController.EventsController.sendEvent({
|
|
616
|
+
type: 'track',
|
|
617
|
+
event: 'SWAP_ERROR',
|
|
618
|
+
properties: {
|
|
619
|
+
message: error?.shortMessage ?? error?.message ?? 'Unknown',
|
|
620
|
+
network: _NetworkController.NetworkController.state.caipNetwork?.id || '',
|
|
621
|
+
swapFromToken: this.state.sourceToken?.symbol || '',
|
|
622
|
+
swapToToken: this.state.toToken?.symbol || '',
|
|
623
|
+
swapFromAmount: this.state.sourceTokenAmount || '',
|
|
624
|
+
swapToAmount: this.state.toTokenAmount || '',
|
|
625
|
+
isSmartAccount: _AccountController.AccountController.state.preferredAccountType === 'smartAccount'
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
return undefined;
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
// -- Checks -------------------------------------------- //
|
|
632
|
+
hasInsufficientToken(sourceTokenAmount, sourceTokenAddress) {
|
|
633
|
+
const isInsufficientSourceTokenForSwap = _SwapCalculationUtil.SwapCalculationUtil.isInsufficientSourceTokenForSwap(sourceTokenAmount, sourceTokenAddress, state.myTokensWithBalance);
|
|
634
|
+
let insufficientNetworkTokenForGas = true;
|
|
635
|
+
if (_AccountController.AccountController.state.preferredAccountType === 'smartAccount') {
|
|
636
|
+
// Smart Accounts may pay gas in any ERC20 token
|
|
637
|
+
insufficientNetworkTokenForGas = false;
|
|
638
|
+
} else {
|
|
639
|
+
insufficientNetworkTokenForGas = _SwapCalculationUtil.SwapCalculationUtil.isInsufficientNetworkTokenForGas(state.networkBalanceInUSD, state.gasPriceInUSD);
|
|
640
|
+
}
|
|
641
|
+
return insufficientNetworkTokenForGas || isInsufficientSourceTokenForSwap;
|
|
642
|
+
},
|
|
643
|
+
// -- Calculations -------------------------------------- //
|
|
644
|
+
setTransactionDetails() {
|
|
645
|
+
const {
|
|
646
|
+
toTokenAddress,
|
|
647
|
+
toTokenDecimals
|
|
648
|
+
} = this.getParams();
|
|
649
|
+
if (!toTokenAddress || !toTokenDecimals) {
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
state.gasPriceInUSD = _SwapCalculationUtil.SwapCalculationUtil.getGasPriceInUSD(state.networkPrice, BigInt(state.gasFee), BigInt(INITIAL_GAS_LIMIT));
|
|
653
|
+
state.priceImpact = _SwapCalculationUtil.SwapCalculationUtil.getPriceImpact({
|
|
654
|
+
sourceTokenAmount: state.sourceTokenAmount,
|
|
655
|
+
sourceTokenPriceInUSD: state.sourceTokenPriceInUSD,
|
|
656
|
+
toTokenPriceInUSD: state.toTokenPriceInUSD,
|
|
657
|
+
toTokenAmount: state.toTokenAmount
|
|
658
|
+
});
|
|
659
|
+
state.maxSlippage = _SwapCalculationUtil.SwapCalculationUtil.getMaxSlippage(state.slippage, state.toTokenAmount);
|
|
660
|
+
state.providerFee = _SwapCalculationUtil.SwapCalculationUtil.getProviderFee(state.sourceTokenAmount);
|
|
89
661
|
}
|
|
90
662
|
};
|
|
91
663
|
//# sourceMappingURL=SwapController.js.map
|