Created
July 13, 2025 11:13
-
-
Save gr1zix/631104c5cf4c589dff523a09e8c763ba to your computer and use it in GitHub Desktop.
FS swap from usdc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const usdcInput = '/html/body/div[1]/div[2]/main/div[1]/div[1]/div/div/div[2]/div/div[1]/div[2]/input'; | |
const reviewSwapButton = '/html/body/div/div[2]/main/div[1]/div[1]/div/div/div[2]/button' | |
const confirmSwapButton = '/html/body/div/div[2]/main/div[1]/div[1]/div/div/div[3]/div[2]/button' | |
async function sendForm(isRetry = false) { | |
try { | |
if (isRetry) { | |
await sleep(200) | |
} | |
if (!isRetry) { | |
const usdcAmountInputElement = getElementByXpath(usdcInput); | |
if (!usdcAmountInputElement) { | |
throw new Error('Amount input not found'); | |
} | |
setReactInputValue(usdcAmountInputElement, getRandomAmount()); | |
await sleep(300); | |
} | |
const reviewSwapButtonElement = await waitForReviewSwapButton(reviewSwapButton); | |
if (!reviewSwapButtonElement) { | |
throw new Error('Add form button not found'); | |
} | |
reviewSwapButtonElement.click() | |
await sleep(150) | |
const confirmSwapButtonEl = getElementByXpath(confirmSwapButton); | |
if (!confirmSwapButtonEl) { | |
await sendForm(true) | |
} | |
confirmSwapButtonEl.click(); | |
await sleep(200) | |
const closeSwapButtonEl = document.querySelector('body > div > div.flex-1.flex.flex-col.overflow-hidden > main > div.flex.flex-col.gap-5.overflow-x-hidden.md\\:gap-7.items-center.pb-5.md\\:pb-10.md\\:pt-7 > div:nth-child(1) > div > div > div.MuiBox-root.css-1is9dp0 > div.MuiBox-root.css-n6dxc2 > svg'); | |
const clickEvent = new MouseEvent('click', { | |
bubbles: true, | |
cancelable: true, | |
view: window, | |
}); | |
closeSwapButtonEl.dispatchEvent(clickEvent); | |
await sleep(100) | |
return true; | |
} catch (error) { | |
console.error('Error during form submission:', error); | |
return false; | |
} | |
} | |
function waitForReviewSwapButton(reviewSwapButton, timeout = 12000) { | |
return new Promise((resolve, reject) => { | |
const element = getElementByXpath(reviewSwapButton); | |
if (element && element.textContent.includes('Review Swap')) { | |
return resolve(element); | |
} | |
const observer = new MutationObserver(() => { | |
const currentElement = getElementByXpath(reviewSwapButton); | |
if (currentElement && currentElement.textContent.includes('Review Swap')) { | |
observer.disconnect(); | |
resolve(currentElement); | |
} | |
}); | |
observer.observe(document.body, { | |
childList: true, | |
subtree: true, | |
characterData: true, | |
}); | |
setTimeout(() => { | |
observer.disconnect(); | |
reject(new Error('Review Swap button not found within timeout')); | |
}, timeout); | |
}); | |
} | |
async function runIterations(iterations, delayBetweenIterationsFrom = 500, delayBetweenIterationsTo = 2000) { | |
let isCancelled = false; | |
let completedIterations = 0; | |
// Function to cancel execution | |
const cancel = () => { | |
isCancelled = true; | |
}; | |
// To be able to cancel from console, we can expose `cancel` function globally | |
window.cancelScript = cancel; | |
console.log("To stop execution, type 'window.cancelScript()' in the console."); | |
for (let i = 0; i < iterations && !isCancelled; i++) { | |
console.log(`Starting iteration ${i + 1}/${iterations}`); | |
const success = await sendForm(); | |
if (!success) { | |
console.log(`Iteration ${i + 1} failed. Stopping.`); | |
break; | |
} | |
completedIterations++; | |
console.log(`Iteration ${i + 1} completed successfully.`); | |
if (i < iterations - 1 && !isCancelled) { | |
const delay = getRandom(delayBetweenIterationsFrom, delayBetweenIterationsTo) | |
console.log(`Waiting for ${delay}ms before next iteration...`); | |
await sleep(delay); | |
} | |
} | |
console.log(`Completed ${completedIterations} of ${iterations} iterations.`); | |
window.cancelScript = undefined; // Clean up | |
return { completed: completedIterations, cancelled: isCancelled }; | |
} | |
function getElementByXpath(path) { | |
return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; | |
} | |
function getRandomAmount(min = 0.5, max = 5) { | |
return (Math.random() * (max - min) + min).toFixed(3); | |
} | |
function getRandom(min, max) { | |
return Math.floor(Math.random() * (max - min) ) + min; | |
} | |
function sleep(ms) { | |
return new Promise(resolve => setTimeout(resolve, ms)); | |
} | |
function setReactInputValue(element, value) { | |
try { | |
if (!element || typeof element.value === 'undefined') { | |
throw new Error('Element is not a valid input'); | |
} | |
const descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); | |
if (!descriptor || !descriptor.set) { | |
element.value = value; | |
element.dispatchEvent(new Event('input', { bubbles: true })); | |
return; | |
} | |
descriptor.set.call(element, value); | |
const events = ['input', 'change', 'blur']; | |
events.forEach(type => { | |
element.dispatchEvent(new Event(type, { bubbles: true })); | |
}); | |
} catch (error) { | |
console.error('Error in setReactInputValue:', error); | |
if (element) { | |
element.value = value; | |
element.dispatchEvent(new Event('input', { bubbles: true })); | |
} | |
} | |
} | |
/** | |
* 30 - iterations | |
* 500 - start of range delay in ms between iterations | |
* 1500 - end of range delay in ms between iterations | |
*/ | |
runIterations(10, 500, 1500); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment