Skip to content

Commit c2e0fd8

Browse files
committed
chore: add inputs for fee, recipient and amount
1 parent 5ca034c commit c2e0fd8

File tree

1 file changed

+203
-19
lines changed

1 file changed

+203
-19
lines changed

src/components/transactions/swapComparison.js

Lines changed: 203 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import globalContext from '../..';
44
// Constants
55
const UNIVERSAL_ROUTER = '0x66a9893cc07d91d95644aedd05d03f95e1dba8af';
66
const USDC_ADDRESS = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
7-
const FEE_RECIPIENT = '0x58c51ee8998e8ef06362df26a0d966bbd0cf5113';
8-
const ETH_AMOUNT = '0x10a741a462780'; // 0.0003 ETH in hex
9-
const FEE_BIPS = 5000; // 50% in basis points
7+
const DEFAULT_FEE_RECIPIENT = '0x58c51ee8998e8ef06362df26a0d966bbd0cf5113';
8+
const DEFAULT_ETH_AMOUNT = '0.0003'; // 0.0003 ETH
9+
const DEFAULT_FEE_PERCENTAGE = 50; // 50%
1010
const EMPTY_BYTES = '0x';
1111

1212
const Actions = {
@@ -42,6 +42,83 @@ const V4_BASE_ACTIONS_ABI_DEFINITION = {
4242
],
4343
};
4444

45+
// Helper functions for input validation and parsing
46+
function isValidAddress(address) {
47+
return ethers.utils.isAddress(address);
48+
}
49+
50+
function parseEthAmount(input) {
51+
const value = input.trim();
52+
if (!value) {
53+
return null;
54+
}
55+
56+
try {
57+
const parsed = parseFloat(value);
58+
if (isNaN(parsed) || parsed < 0) {
59+
return null;
60+
}
61+
// Convert ETH to wei and then to hex
62+
return ethers.utils.parseEther(value.toString()).toHexString();
63+
} catch {
64+
return null;
65+
}
66+
}
67+
68+
function parseFeePercentage(input) {
69+
const value = input.trim();
70+
if (!value) {
71+
return null;
72+
}
73+
74+
try {
75+
const parsed = parseFloat(value);
76+
if (isNaN(parsed) || parsed < 0 || parsed > 100) {
77+
return null;
78+
}
79+
// Convert percentage to basis points (1% = 100 basis points)
80+
return Math.round(parsed * 100);
81+
} catch {
82+
return null;
83+
}
84+
}
85+
86+
function getConfigValues() {
87+
const feeRecipientElement = document.getElementById('feeRecipientInput');
88+
const ethAmountElement = document.getElementById('ethAmountInput');
89+
const feePercentageElement = document.getElementById('feePercentageInput');
90+
91+
const feeRecipientInput = feeRecipientElement
92+
? feeRecipientElement.value.trim()
93+
: '';
94+
const ethAmountInput = ethAmountElement ? ethAmountElement.value.trim() : '';
95+
const feePercentageInput = feePercentageElement
96+
? feePercentageElement.value.trim()
97+
: '';
98+
99+
// Use defaults if inputs are empty or invalid
100+
const feeRecipient =
101+
feeRecipientInput && isValidAddress(feeRecipientInput)
102+
? feeRecipientInput
103+
: DEFAULT_FEE_RECIPIENT;
104+
105+
const ethAmountHex =
106+
parseEthAmount(ethAmountInput) ||
107+
ethers.utils.parseEther(DEFAULT_ETH_AMOUNT).toHexString();
108+
109+
const feeBips =
110+
parseFeePercentage(feePercentageInput) || DEFAULT_FEE_PERCENTAGE * 100;
111+
112+
return {
113+
feeRecipient,
114+
ethAmountHex,
115+
feeBips,
116+
ethAmountDisplay: ethAmountInput || DEFAULT_ETH_AMOUNT,
117+
feePercentageDisplay:
118+
feePercentageInput || DEFAULT_FEE_PERCENTAGE.toString(),
119+
};
120+
}
121+
45122
function createAction(action, parameters) {
46123
const encodedInput = ethers.utils.defaultAbiCoder.encode(
47124
V4_BASE_ACTIONS_ABI_DEFINITION[action].map((v) => v.type),
@@ -72,22 +149,87 @@ export function swapComparisonComponent(parentContainer) {
72149
</h4>
73150
74151
<p class="info-text alert alert-warning">
75-
⚠️ This swap includes a 50% fee deduction for testing purposes
152+
⚠️ This swap includes a high fee for testing purposes
76153
</p>
77154
78155
<div class="alert alert-secondary">
79-
<strong>Swap Details:</strong><br/>
80-
• From: 0.0003 ETH<br/>
156+
<strong>Current Swap Details:</strong><br/>
157+
<span id="swapDetailsDisplay">
158+
• From: <span id="displayEthAmount">${DEFAULT_ETH_AMOUNT}</span> ETH<br/>
81159
• To: USDC<br/>
82-
• Fee: 50% of output
160+
• Fee: <span id="displayFeePercentage">${DEFAULT_FEE_PERCENTAGE}</span>% of output
161+
</span>
162+
</div>
163+
164+
<!-- Configuration Section -->
165+
<div class="card mb-3" style="background-color: #f8f9fa;">
166+
<div class="card-body">
167+
<h6 class="card-subtitle mb-3 text-muted">
168+
<strong>Configuration (Optional)</strong>
169+
</h6>
170+
171+
<div class="form-group mb-3">
172+
<label for="ethAmountInput" style="font-size: 0.9em;">
173+
<strong>ETH Amount</strong>
174+
</label>
175+
<input
176+
type="number"
177+
class="form-control"
178+
id="ethAmountInput"
179+
placeholder="${DEFAULT_ETH_AMOUNT}"
180+
step="0.0001"
181+
min="0"
182+
style="font-size: 0.9em;"
183+
/>
184+
<small class="form-text text-muted">Leave empty for default (${DEFAULT_ETH_AMOUNT} ETH)</small>
185+
</div>
186+
187+
<div class="form-group mb-3">
188+
<label for="feePercentageInput" style="font-size: 0.9em;">
189+
<strong>Fee Percentage</strong>
190+
</label>
191+
<input
192+
type="number"
193+
class="form-control"
194+
id="feePercentageInput"
195+
placeholder="${DEFAULT_FEE_PERCENTAGE}"
196+
step="1"
197+
min="0"
198+
max="100"
199+
style="font-size: 0.9em;"
200+
/>
201+
<small class="form-text text-muted">Leave empty for default (${DEFAULT_FEE_PERCENTAGE}%)</small>
202+
</div>
203+
204+
<div class="form-group mb-3">
205+
<label for="feeRecipientInput" style="font-size: 0.9em;">
206+
<strong>Fee Recipient Address</strong>
207+
</label>
208+
<input
209+
type="text"
210+
class="form-control"
211+
id="feeRecipientInput"
212+
placeholder="${DEFAULT_FEE_RECIPIENT}"
213+
style="font-size: 0.85em; font-family: monospace;"
214+
/>
215+
<small class="form-text text-muted">Leave empty for default address</small>
216+
</div>
217+
218+
<button
219+
class="btn btn-sm btn-secondary btn-block"
220+
id="resetConfigButton"
221+
>
222+
Reset to Defaults
223+
</button>
224+
</div>
83225
</div>
84226
85227
<button
86228
class="btn btn-primary btn-lg btn-block mb-3"
87229
id="swapComparisonSwapButton"
88230
disabled
89231
>
90-
Swap ETH to USDC (50% Fee)
232+
Swap ETH to USDC
91233
</button>
92234
93235
<p class="info-text alert alert-secondary">
@@ -105,6 +247,31 @@ export function swapComparisonComponent(parentContainer) {
105247
const swapButton = document.getElementById('swapComparisonSwapButton');
106248
const statusDisplay = document.getElementById('swapStatus');
107249
const txHashDisplay = document.getElementById('swapTxHash');
250+
const resetButton = document.getElementById('resetConfigButton');
251+
const ethAmountInput = document.getElementById('ethAmountInput');
252+
const feePercentageInput = document.getElementById('feePercentageInput');
253+
const feeRecipientInput = document.getElementById('feeRecipientInput');
254+
const displayEthAmount = document.getElementById('displayEthAmount');
255+
const displayFeePercentage = document.getElementById('displayFeePercentage');
256+
257+
// Function to update the swap details display
258+
function updateSwapDetailsDisplay() {
259+
const config = getConfigValues();
260+
displayEthAmount.textContent = config.ethAmountDisplay;
261+
displayFeePercentage.textContent = config.feePercentageDisplay;
262+
}
263+
264+
// Add event listeners for input changes to update display
265+
ethAmountInput.addEventListener('input', updateSwapDetailsDisplay);
266+
feePercentageInput.addEventListener('input', updateSwapDetailsDisplay);
267+
268+
// Reset button handler
269+
resetButton.addEventListener('click', function () {
270+
ethAmountInput.value = '';
271+
feePercentageInput.value = '';
272+
feeRecipientInput.value = '';
273+
updateSwapDetailsDisplay();
274+
});
108275

109276
document.addEventListener('globalConnectionChange', function (e) {
110277
if (e.detail.connected) {
@@ -122,25 +289,38 @@ export function swapComparisonComponent(parentContainer) {
122289
swapButton.onclick = async () => {
123290
try {
124291
statusDisplay.innerHTML = 'Building transaction...';
292+
293+
// Get configuration values from inputs or use defaults
294+
const config = getConfigValues();
295+
125296
console.log('=== Swap Comparison Transaction ===');
126297
console.log('Router:', UNIVERSAL_ROUTER);
127-
console.log('ETH Amount:', ETH_AMOUNT, '(0.0003 ETH)');
128-
console.log('Fee Recipient:', FEE_RECIPIENT);
129-
console.log('Fee %:', FEE_BIPS / 100, '%');
298+
console.log(
299+
'ETH Amount:',
300+
config.ethAmountHex,
301+
`(${config.ethAmountDisplay} ETH)`,
302+
);
303+
console.log('Fee Recipient:', config.feeRecipient);
304+
console.log('Fee %:', config.feeBips / 100, '%');
130305

131306
// Use working example as template and modify only necessary values
132307
const deadline = Math.floor(Date.now() / 1000) + 1200; // 20 minutes from now
133308

134309
// Build calldata using template from working example
135-
const data = buildCalldata(deadline, FEE_RECIPIENT, FEE_BIPS);
310+
const data = buildCalldata(
311+
deadline,
312+
config.feeRecipient,
313+
config.feeBips,
314+
config.ethAmountHex,
315+
);
136316

137317
statusDisplay.innerHTML = 'Sending transaction...';
138318

139319
// Send the transaction
140320
const txParams = {
141321
from: globalContext.accounts[0],
142322
to: UNIVERSAL_ROUTER,
143-
value: ETH_AMOUNT,
323+
value: config.ethAmountHex,
144324
data,
145325
};
146326

@@ -166,16 +346,20 @@ export function swapComparisonComponent(parentContainer) {
166346

167347
/**
168348
* Build calldata using the working example as a template
169-
* Only modifies: deadline, fee recipient, fee bips, and user address
349+
* Only modifies: deadline, fee recipient, fee bips, eth amount, and user address
170350
*/
171-
function buildCalldata(deadline, feeRecipient, feeBips) {
351+
function buildCalldata(deadline, feeRecipient, feeBips, ethAmount) {
172352
// Working example from the original transaction
173353
// We'll use ethers to properly encode with our values
174354
const commands = '0x10'; // V4_SWAP
175355

176356
// V4_SWAP input - extracted from working example
177357
// This is the complex nested structure that we keep as-is
178-
const v4SwapInput = buildV4SwapInputFromExample(feeRecipient, feeBips);
358+
const v4SwapInput = buildV4SwapInputFromExample(
359+
feeRecipient,
360+
feeBips,
361+
ethAmount,
362+
);
179363

180364
// Encode the execute function call
181365
const inputs = [v4SwapInput]; //, payPortionInput, sweepInput];
@@ -197,7 +381,7 @@ function buildCalldata(deadline, feeRecipient, feeBips) {
197381
* Build V4_SWAP input from working example structure
198382
* This uses the exact structure from a known working transaction
199383
*/
200-
function buildV4SwapInputFromExample(feeRecipient, feeBips) {
384+
function buildV4SwapInputFromExample(feeRecipient, feeBips, ethAmount) {
201385
// From working example: actions = 0x070b0e
202386
let v4Actions = EMPTY_BYTES;
203387
const v4Params = [];
@@ -219,7 +403,7 @@ function buildV4SwapInputFromExample(feeRecipient, feeBips) {
219403
{
220404
poolKey,
221405
zeroForOne: true, // The direction of swap is ETH to USDC. Change it to 'false' for the reverse direction
222-
amountIn: ETH_AMOUNT,
406+
amountIn: ethAmount,
223407
amountOutMinimum, // Change according to the slippage desired
224408
hookData: '0x00',
225409
},
@@ -229,7 +413,7 @@ function buildV4SwapInputFromExample(feeRecipient, feeBips) {
229413

230414
const settleAll = addAction(Actions.SETTLE_ALL, [
231415
poolKey.currency0,
232-
ETH_AMOUNT,
416+
ethAmount,
233417
]);
234418
v4Actions = v4Actions.concat(settleAll.newAction);
235419
v4Params.push(settleAll.newParam);

0 commit comments

Comments
 (0)