This repository has been archived by the owner on Mar 16, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
trade.js
364 lines (284 loc) · 11 KB
/
trade.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
// ### Variable Definition ###
var web3 = new Web3(Web3.givenProvider);
var utils = web3.utils;
// HTML elements to add and delete
// Loader
loader = `<div class="loader"></div>`;
swapButtonDiv = document.querySelector('.swap-button-div');
swapButton = document.querySelector('#swap-button');
swapButtonHtml = `<input class="btn btn-outline-light" id="swap-button" type="submit" value="SWAP">`;
const metaMaskBtn = document.querySelector('#metamask-button')
const closeBtn = document.querySelector('#close-button')
const modalTitle = document.querySelector('.modal-header')
const modalBody = document.querySelector('.modal-body')
const maxDestAmount = "10000000000000000000000000000000"
// For fee sharing program
const walletId = "0x1bF3e7EDE31dBB93826C2aF8686f80Ac53f9ed93"
// Ether balance to update it according to the addresses ether balance
let etherBalance;
// TO check whether proposed Gas price is lower than 10, if so, set to 10 automatically
let defaultGasPrice;
let chosenGasPrice;
// Define variable successful, which if set to false, will stop after the first tx and avoid asking to user to confirm the second one.
let successful;
// Counter to protect users from creating two event listeners on the swap button that will result in 2 tx's to be signed
let counter = 0
// ############# Functions ###############
// Function to be called after the final event has been triggered
function reloadMainPage() {
location.reload();
};
// Change Swap to Loader and back
// Change Swap button to Loader
function swapToLoader() {
swapButton.style.display = "none";
swapButtonDiv.insertAdjacentHTML("afterbegin", loader);
}
// Change Loader back to Swap Button
function loaderToSwap() {
document.querySelector('.loader').remove();
swapButton.style.display = "";
}
// Check if web3 is injected
window.addEventListener('load', function () {
if (typeof web3 !== 'undefined' && web3.currentProvider !== null) {
console.log('web3 is enabled')
if (web3.currentProvider.isMetaMask === true) {
console.log('MetaMask is active')
} else {
console.log('MetaMask is not available')
}
// opens web3 client
ethereum.enable();
// Change modal to only show title and close button
modalBody.style.display = "none";
metaMaskBtn.style.display = "none";
} else {
// Change inner HTML of Error message
console.log('web3 is not found')
console.log('Please install Metamask')
$('.modal').modal('show');
// Create Error Message
}
})
// Check if client is on the right network and create alert if not
web3.eth.net.getNetworkType()
.then((result) => {
if (`${result}` == "main" && selectedEthereumNetwork == "ropsten") {
modalTitle.innerText = "Please switch your web3 client to the Ropsten Testnet";
$('.modal').modal('show');
} else if (`${result}` == "ropsten" && selectedEthereumNetwork == "mainnet") {
modalTitle.innerText = "Please switch your web3 client to the Mainnet";
$('.modal').modal('show');
} else if (`${result}` == "ropsten" && selectedEthereumNetwork == "ropsten") {
return 0;
} else if (`${result}` == "main" && selectedEthereumNetwork == "mainnet") {
return 0;
} else {
modalTitle.innerText = "Please switch your web3 client to either Mainnet or Ropsten";
$('.modal').modal('show');
}
})
// Set ETH Balance to show on front end
async function setEthBalance(fetchedUserAddress) {
etherBalance = await web3.eth.getBalance(fetchedUserAddress)
if (addressToSell == "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") {
document.getElementById('sell-max-token').innerText = `Max: ${(etherBalance / 10 ** srcDecimal).toFixed(5)} ${srcSymbol}`
}
}
async function getEthereumGasPrice() {
defaultGasPrice = await web3.eth.getGasPrice()
chosenGasPrice = (defaultGasPrice < 10000000000) ? `${10000000000}` : `${defaultGasPrice}`;
}
getEthereumGasPrice()
// Check if user swapped web3 accounts & Set initial Ether Balance
function newMetaMaskAddress(error, data) {
fetchedUserAddress = `${error['selectedAddress']}`
if (fetchedUserAddress !== "undefined") setEthBalance(fetchedUserAddress);
}
web3.currentProvider.publicConfigStore.on('update', newMetaMaskAddress);
// ################ Ether => ERC20 Trade ###################
async function executeEtherTx() {
console.log(srcAmountWei)
transactionData = kyberNetworkProxyContract.methods.trade(
addressToSell, //ETH srcToken
srcAmountWei, //uint srcAmount
addressToBuy, //ERC20 destToken
fetchedUserAddress, //address destAddress => VENDOR_WALLET_ADDRESS
maxDestAmount, //uint maxDestAmount
slippageRate, //uint minConversionRate
walletId //uint walletId
).encodeABI();
txReceipt = await web3.eth.sendTransaction({
from: fetchedUserAddress, //obtained from website interface Eg. Metamask, Ledger etc.
to: kyberNetworkProxyAddress,
data: transactionData,
value: srcAmountWei, //ADDITIONAL FIELD HERE
gasPrice: chosenGasPrice
})
// When the user clicks confirm in Metamask and the transcation hash is broadcasted
.on('transactionHash', function (hash) {
waitingModal(hash)
})
.catch(function (error) {
console.log(error);
// Reload page to avoid having multiple tx queued up
canceledTxModal();
successful = false;
})
// IF tx was abondend, do dont show succesfull Modal
closeBtn.removeEventListener("click", executeEtherTx, {
passive: true
});
if (successful == false) return 0;
successfulModal()
var templateParams = {
srcToken: srcSymbol,
destToken: destSymbol,
srcQuantity: srcAmount,
destQuantity: destAmount,
network: selectedEthereumNetwork
}
// Send anonymous notifcation that a tx was triggered
emailjs.send('default_service', 'template_EFJQRdCL', templateParams, 'user_xN7N3ZJAOLHhHiviFcV1H');
}
// ####################################
// ####### Trade() ERC20 => ERC20 #######
async function executeTx() {
// ####### Start second tx ########
// Call the trade method in Proxy Contract
transactionData2 = kyberNetworkProxyContract.methods.trade(
addressToSell, //ERC20 srcToken
srcAmountWei, //uint srcAmount
addressToBuy, //ERC20 destToken
fetchedUserAddress, //address destAddress => VENDOR_WALLET_ADDRESS
maxDestAmount, //uint maxDestAmount
slippageRate, //uint minConversionRate
walletId //uint walletId for fee sharing program
).encodeABI()
// estimatedGasLimit = await web3.eth.estimateGas({
// to: addressToBuy,
// data: transactionData2
// })
txReceipt = await web3.eth.sendTransaction({
from: fetchedUserAddress,
to: kyberNetworkProxyAddress,
data: transactionData2,
nonce: nonce 1,
gas: 600000,
gasPrice: chosenGasPrice
}, function (error, hash) {
waitingModal(hash)
})
.catch(function (error) {
console.log(error);
canceledTxModal();
successful = false;
});
// Open modal that display tx was successful
closeBtn.removeEventListener('click', executeTx, {
passive: true
});
// Only show successful modal when trade was executed
if (successful == false) return 0;
successfulModal()
var templateParams = {
srcToken: srcSymbol,
destToken: destSymbol,
srcQuantity: srcAmount,
destQuantity: destAmount,
network: selectedEthereumNetwork
}
// Send anonymous notifcation that a tx was triggered
emailjs.send('default_service', 'template_EFJQRdCL', templateParams, 'user_xN7N3ZJAOLHhHiviFcV1H');
// End of Async
}
// ### Approve TX ERC 20 => ERC220 #######
async function approveTx() {
transactionData1 = srcTokenContract.methods.approve(kyberNetworkProxyAddress, srcAmountWei).encodeABI()
txReceipt = await web3.eth.sendTransaction({
from: fetchedUserAddress, //obtained from website interface Eg. Metamask, Ledger etc.
to: addressToSell, //srcTokenContract resluted in error as it did not provide the contracts address, but the object itself,
data: transactionData1,
gasPrice: chosenGasPrice,
nonce: nonce
}, function (error, hash) {
tradeApprovedModal()
// Remove first event listener
closeBtn.removeEventListener("click", approveTx, {
passive: true
});
// Add event Listener to function
closeBtn.addEventListener('click', executeTx)
})
.catch(function (error) {
console.log(error);
successful = false;
closeBtn.removeEventListener("click", executeTx, {
passive: true
});
canceledTxModal()
})
if (successful == false) return 0;
}
// Let the trade begin
async function trade() {
// Check if source Amount is greater than 0
if (srcAmount == 0) {
zeroModal();
return 0
}
srcAmountWei = `${srcAmount * (10 ** parseInt(srcDecimal))}`;
// Set successful to true
successful = true;
/*### TRADE EXECUTION ####*/
// If User chooses to sell ETH
if (addressToSell == "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") {
// Check if user has sufficient ether available
let etherBalance = await web3.eth.getBalance(fetchedUserAddress)
if (etherBalance >= parseInt(srcAmountWei)) {
startModal()
counter = 1;
// Only add the Event Listener once, to avoid multiple tx popping up if user hits swap multiple times
if (counter < 2) closeBtn.addEventListener('click', executeEtherTx);
// If not, dont execute trade
} else {
insufficientFundsModal()
}
// ##############################################################
// If User chooses to sell ERC20 TOken
} else {
// IF user has enough funds of the selected Token, start the process
if (erc20tokenBalance >= parseInt(srcAmountWei)) {
// Check if User gave Kyber any allowance in order to skip allow tx
allowanceAmount = await srcTokenContract.methods.allowance(fetchedUserAddress, kyberNetworkProxyAddress).call()
// Set nonce
nonce = await web3.eth.getTransactionCount(fetchedUserAddress);
// Iterate on counter to prevent 2 tx popping up for one
counter = 1;
// If User already approved Kyber to exchange tokens, skip the approval() method
if (srcAmountWei <= allowanceAmount) {
// console.log(`Source Amount: ${srcAmountWei} is smaller than AllowanceAmount ${allowanceAmount}`)
// Open respective Modal
skippedApprovalModal();
// Create event listener that calls executeTx function
if (counter < 2) closeBtn.addEventListener('click', executeTx)
// If User has not approved Kyber to trade tokens, call approval first
} else {
// console.log(`Source Amount: ${srcAmountWei} is greater than AllowanceAmount ${allowanceAmount}`)
startModal();
// Create event listener that calls executeTx function
if (counter < 2) closeBtn.addEventListener('click', approveTx)
}
// If token balance is less then srcAmount, stopp the trade
} else {
insufficientFundsModal()
}
}
// trade() end
}
const tradeButton = document.querySelector("#swap-button");
tradeButton.addEventListener('click', function (event) {
event.preventDefault();
trade();
});