Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add an approval/funding UI #30

Open
wants to merge 53 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
bc37549
feat: rollback to template
zugdev Nov 20, 2024
6719d29
chore: install dependencies
zugdev Nov 21, 2024
dc3aaaa
feat: base UI
zugdev Nov 21, 2024
68e1715
feat: add network button
zugdev Nov 21, 2024
a220ca3
feat: add chains
zugdev Nov 21, 2024
f6a4e17
chore: format
zugdev Nov 21, 2024
4571b5e
feat: basic styiling and form
zugdev Nov 21, 2024
287505d
feat: add current allowance
zugdev Nov 21, 2024
a3caa79
feat: add neon border
zugdev Nov 26, 2024
9634f81
feat: add token-selector and change expected allowance
zugdev Nov 26, 2024
edd0772
feat: fix token selector
zugdev Nov 26, 2024
3befb07
feat: update dropdown tokens based on network
zugdev Nov 26, 2024
03b9dcf
feat: add erc20 abi
zugdev Nov 26, 2024
6fd952e
feat: rollback to current allowance
zugdev Nov 26, 2024
9d1ffb8
feat: add permit2 address table
zugdev Nov 26, 2024
19f3bbf
feat: add web3 integration
zugdev Nov 26, 2024
5b93446
feat: initially disabled
zugdev Nov 26, 2024
5f48675
feat: better error modal
zugdev Nov 26, 2024
18adb4e
feat: all providers
zugdev Dec 13, 2024
1337208
chore: pull alchemy key from secrets on build
zugdev Dec 13, 2024
3c77a03
chore: yarn
zugdev Dec 18, 2024
6478209
feat: make ALCHEMY_KEY optional
zugdev Dec 18, 2024
4605da3
feat: enable anvil in localhost
zugdev Dec 18, 2024
e2149ad
chore: prettier
zugdev Dec 18, 2024
89b0f04
feat: batch update
zugdev Dec 21, 2024
ba36a2c
feat: responsivity
zugdev Dec 21, 2024
6bec149
chore: fix eslint version
zugdev Dec 21, 2024
1f81afa
Merge branch 'development' of https://github.com/zugdev/onboard.ubq.f…
zugdev Dec 21, 2024
8ea7037
chore: unlog
zugdev Dec 21, 2024
7878d48
feat: fix signer
zugdev Dec 21, 2024
fa44c95
feat: loading while minting tx
zugdev Dec 21, 2024
f421786
feat: capitalize
zugdev Dec 21, 2024
c526d60
feat: get rid of chainId
zugdev Dec 21, 2024
b5c844a
feat: remove button setup
zugdev Dec 21, 2024
f801b95
feat: better naming
zugdev Dec 21, 2024
3ffcf15
feat: add reference for zksync permit2 address
zugdev Dec 21, 2024
bded1b3
feat: use actions/create-github-app-token
zugdev Dec 21, 2024
8f8fa38
feat: getAllowance on address only
zugdev Dec 21, 2024
c22af00
feat: add success modal
zugdev Dec 21, 2024
c0ca66d
feat: success pop up
zugdev Dec 21, 2024
228f7d1
chore: fix jest
zugdev Dec 26, 2024
834b8dd
feat: add explorers map
zugdev Dec 26, 2024
1bd7ca8
feat: render success in revoke
zugdev Dec 26, 2024
8105aab
feat: add tx linkback in success
zugdev Dec 26, 2024
9299ea3
feat: remove alchemy from deploy
zugdev Dec 26, 2024
23f3344
chore: fix knip
zugdev Dec 26, 2024
f04f3d1
chore: typo
zugdev Dec 26, 2024
656e862
chore: missing div
zugdev Dec 26, 2024
58edb53
Merge branch 'development' of github.com:zugdev/onboard.ubq.fi into d…
zugdev Dec 26, 2024
c906697
feat: const
zugdev Jan 9, 2025
78fb771
chore: delete outdated
zugdev Jan 9, 2025
b525724
feat: feedback on erc20 fail
zugdev Jan 9, 2025
326dbc2
chore: cspell
zugdev Jan 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"ignorePaths": ["**/*.json", "**/*.css", "node_modules", "**/*.log"],
"useGitignore": true,
"language": "en",
"words": ["dataurl", "devpool", "outdir", "servedir"],
"words": ["dataurl", "devpool", "outdir", "servedir", "TYPEHASH", "noopener", "noreferrer", "reown", "appkit", "zksync", "worldchain", "Caip", "UUSD"],
"dictionaries": ["typescript", "node", "software-terms"],
"import": ["@cspell/dict-typescript/cspell-ext.json", "@cspell/dict-node/cspell-ext.json", "@cspell/dict-software-terms"],
"ignoreRegExpList": ["[0-9a-fA-F]{6}"]
Expand Down
53 changes: 32 additions & 21 deletions static/handle-approval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ const currentAllowanceAmount = document.querySelector(".current-allowance-amount
const approveButton = document.querySelector(".approve-button") as HTMLButtonElement;
const revokeButton = document.querySelector(".revoke-button") as HTMLButtonElement;

const red = "1px solid red";
const green = "1px solid #5af55a";
const grey = "1px solid rgba(255, 255, 255, 0.1)";

function isValidAddress(): boolean {
//reset color
addressInput.style.border = grey;

const isValid = /^0x[a-fA-F0-9]{40}$/.test(addressInput.value);

if (isValid) {
addressInput.style.border = "1px solid #5af55a";
} else if (addressInput.value === "") {
addressInput.style.border = "1px solid rgba(255, 255, 255, 0.1)";
} else {
addressInput.style.border = "1px solid red";
if (!isValid && addressInput.value !== "") {
addressInput.style.border = red;
}

return isValid;
Expand All @@ -28,33 +31,41 @@ function isValidAmount(): boolean {
const isValid = !isNaN(Number(amountInput.value)) && Number(amountInput.value) > 0;

if (isValid) {
amountInput.style.border = "1px solid #5af55a";
amountInput.style.border = green;
} else if (amountInput.value === "") {
amountInput.style.border = "1px solid rgba(255, 255, 255, 0.1)";
amountInput.style.border = grey;
} else {
amountInput.style.border = "1px solid red";
amountInput.style.border = red;
}

return isValid;
}

export function isApprovalButtonsValid() {
export async function isApprovalButtonsValid() {
currentAllowanceAmount.textContent = "...";
const isConnected = appState.getIsConnectedState();
const isAddressValid = isValidAddress();
const isAmountValid = isValidAmount();

approveButton.disabled = !(isConnected && isAddressValid && isAmountValid);
revokeButton.disabled = !(isConnected && isAddressValid);
approveButton.disabled = true;
revokeButton.disabled = true;

if (isAddressValid && isConnected) {
void getCurrentAllowance();
const isSuccess = await getCurrentAllowance();
if (isSuccess) {
approveButton.disabled = !isAmountValid;
revokeButton.disabled = false;
addressInput.style.border = green;
} else {
addressInput.style.border = red;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now every time I click out of the amount input, the buttons get disabled until allowance is fetched and it's a weird UX

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but thats what you meant by checking if its an erc20 token, should I add a spinner to indicate loading perhaps?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought you will do the check when approve button is clicked and then it would show the error modal.

}
}

async function getCurrentAllowance() {
async function getCurrentAllowance(): Promise<boolean> {
if (!provider) {
console.error("Provider is not initialized");
return;
return false;
}

const tokenAddress = addressInput.value;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you might wanna check if the address is ERC20 because if put a random address then it throws a revert error and it can be confusing to the users

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

managed that, thanks

Expand All @@ -68,10 +79,10 @@ async function getCurrentAllowance() {
const allowance = await tokenContract.allowance(userAddress, permit2Address);
const formattedAllowance = ethers.utils.formatUnits(allowance, decimals);
currentAllowanceAmount.textContent = formattedAllowance + " " + symbol;
return allowance;
return true;
} catch (error) {
console.error("Error fetching allowance:", error);
renderErrorInModal(error as Error);
currentAllowanceAmount.textContent = "not a valid token";
return false;
}
}

Expand Down Expand Up @@ -109,7 +120,7 @@ async function onApproveClick() {
renderErrorInModal(error as Error);
} finally {
approveButton.textContent = originalText;
isApprovalButtonsValid(); // re-check the state to restore buttons correctly
await isApprovalButtonsValid(); // re-check the state to restore buttons correctly
}
}

Expand Down Expand Up @@ -145,11 +156,11 @@ async function onRevokeClick() {
renderErrorInModal(error as Error);
} finally {
revokeButton.textContent = originalText;
isApprovalButtonsValid(); // re-check state to restore buttons correctly
await isApprovalButtonsValid(); // re-check state to restore buttons correctly
}
}

export function setupButtonValidityListener() {
export async function setupButtonValidityListener() {
amountInput.addEventListener("change", isApprovalButtonsValid);
addressInput.addEventListener("change", isApprovalButtonsValid);
}
4 changes: 2 additions & 2 deletions static/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ async function initializeProviderAndSigner() {
}

// update UI elements that depend on connection state
isApprovalButtonsValid();
await isApprovalButtonsValid();
updateTokenDropdown();
}

Expand All @@ -122,7 +122,7 @@ function handleNetworkSwitch() {

export async function mainModule() {
try {
setupButtonValidityListener();
await setupButtonValidityListener();
updateTokenDropdown();
setupApproveButton();
setupRevokeButton();
Expand Down
4 changes: 1 addition & 3 deletions static/populate-dropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ const tokenOptions = document.querySelector("#token-options") as HTMLSelectEleme
export function updateTokenDropdown() {
const networkId = Number(appState.getChainId());

let tokens = {};

tokens = tokensByNetwork[networkId] || {};
const tokens = tokensByNetwork[networkId] || {};

if (tokenSelector && tokenOptions) {
tokenOptions.innerHTML = ""; // Clear existing options
Expand Down
19 changes: 0 additions & 19 deletions test-dashboard.md
zugdev marked this conversation as resolved.
Outdated
Show resolved Hide resolved

This file was deleted.

Loading